def extend(serie, endpoint, newname, past=capacity_factor_past, future=capacity_factor_PDP7A): """Extend a series by interpolating between 2020, 2025, 2030 and a 2050 endpoint.""" r = past[serie] a = (r.loc[2013] + r.loc[2014] + r.loc[2015]) / 15 b = future.loc[2020, serie] / 5 c = future.loc[2025, serie] / 5 d = future.loc[2030, serie] / 5 s = pd.Series(name=newname, data=[ 4 * a + b, 3 * a + 2 * b, 2 * a + 3 * b, a + 4 * b, 5 * b, 4 * b + c, 3 * b + 2 * c, 2 * b + 3 * c, b + 4 * c, 5 * c, 4 * c + d, 3 * c + 2 * d, 2 * c + 3 * d, c + 4 * d, 5 * d ], index=range(2016, 2031)) r = r.append(s) d *= 5 e = endpoint s = pd.Series(name=newname, data=[d + (e - d) * (i + 1) / 20 for i in range(20)], index=range(2031, 2051)) return r.append(s)
def residual_value(additions, plant_accounting_life, technology): """Return the residual value of the generation capacity at model end year. A Series equal 0 for all years except at the end. """ lifetime = plant_accounting_life[technology] idx = additions.index n = len(idx) remaining_fraction = pd.Series(0, index=idx) for i in range(min(lifetime, n)): # On average, plant opens middle of the year remaining_fraction.iloc[n - i - 1] = 1 - (i + 0.5) / lifetime result = pd.Series(0, index=years, name=technology) result[2050] = (remaining_fraction * additions[technology]).sum() return result
def by_median(fuel, col): """Median of observed costs, defined as 'refering to a year prior year of publication'.""" data = view[fuel] past_data = data[data.Year < data.PublicationYear] s = pd.Series(past_data[col].median(), index=years, name=fuel) if VERBOSE: myplot(data, fuel, col, s, " (median of " + str(len(past_data)) + ") ") return s
def fill_in(serie): """Return the investments needed to reach the capacity objectives. Approximately because cast as integer """ capacity_2015 = capacity_past.cumsum().loc[2015, serie.name] a = (serie[2020] - capacity_2015) / 15 b = (serie[2025] - serie[2020]) / 15 c = (serie[2030] - serie[2025]) / 15 return pd.Series(name=serie.name, data=[ a, 2 * a, 3 * a, 4 * a, 5 * a, b, 2 * b, 3 * b, 4 * b, 5 * b, c, 2 * c, 3 * c, 4 * c, 5 * c ], index=range(2016, 2031), dtype="int64")
def by_regression(fuel, col): """Regression, when the literature forecasts cost saving technical progress.""" data = view[fuel] explaining = data.Year - start_year explaining = sm.add_constant(explaining) model = sm.OLS(data[col], explaining, missing='drop') results = model.fit() show(fuel, results.summary()) level = results.params.const trend = results.params.Year if results.pvalues.Year < 0.05 else 0 s = pd.Series(np.linspace(level, level + trend * n_year, n_year), index=years, name=fuel) if VERBOSE: myplot(data, fuel, col, s, " (regression on " + str(len(data)) + ") ") return s
def smooth(s): """Redistribute over time equally a mass concentrated in the last period. Argument s is a numerical series with a numerical value in last position. Values are and remain integers; Metaphor: the benjamin shares apples with all his previous siblings. Assume for example there are 4 brothers and the last one has 10 apples. Then he should give each brother 2 apples, keeping 4 for himself. >>> smooth(pd.Series([0, 0, 0, 10])) 0 2 1 2 2 2 3 4 dtype: int64 """ n = len(s) total = s.iloc[-1] annual = int(total // n) final = int(total - annual * (n - 1)) data = [annual] * (n - 1) + [final] assert sum(data) == total return pd.Series(data, s.index)
of the electricity production (3.7%). The figure adds that: Imports represented 1.5%, we infer that the production number is the total domestic supply. The Gas cheese slice label is "Gas Turbine" which includes Oil fueled gas turbines. """ # This implies a total production of 164310 * 0.985 = 161.8 TWh # which compares to 159.7 TWh given in EVN 2016 report page 16 domestic_supply_2015 = 164310 # GWh production_2015 = pd.Series(name=2015, data={ "Coal": round(0.344 * domestic_supply_2015), "BigHydro": round(0.304 * domestic_supply_2015), "GasTurbine": round(0.300 * domestic_supply_2015), "Renewable4": round(0.037 * domestic_supply_2015), "Import": round(0.015 * domestic_supply_2015) }) production_2015[ "Oil"] = 450 # Source: Own estimate, same as 2015, we have no idea production_2015["Gas"] = production_2015["GasTurbine"] - production_2015["Oil"] production_2015["Wind"] = 240 # Source: Own estimate, 2014 + Bac Lieu 1 online production_2015["Biomass"] = 60 # Continuity with 2014 level and trend production_2015["Solar"] = 0 # Commercial solar power not allowed by law yet addcol_Renewable(production_2015) production_2015["SmallHydro"] = production_2015[ "Renewable4"] - production_2015["Renewable"]
CO2_captured = CO2_produced - CO2_emitted CO2_emitted = EMISSION_FACTOR_withCCS * production CO2_produced = CO2_factor_of_heat * heat_used CO2_produced = CO2_factor_of_heat * production * heat_rate_CCS CO2_produced = CO2_factor_of_heat * production * heat_rate_noCCS * (1 + energy_penalty) CO2_produced = production * EMISSION_FACTOR_noCCS * (1 + energy_penalty) CO2_captured = production * capture_factor capture_factor = EMISSION_FACTOR_noCCS * (1 + energy_penalty) - EMISSION_FACTOR_withCCS """ capture_factor = pd.DataFrame(index=YEARS) for fuel in SOURCES: capture_factor[fuel] = pd.Series(0, index=YEARS) # gCO2/ kWh capture_factor["CoalCCS"] = (EMISSION_FACTOR["Coal"] * (1 + energy_penalty) - EMISSION_FACTOR["CoalCCS"]) capture_factor["GasCCS"] = (EMISSION_FACTOR["Gas"] * (1 + energy_penalty) - EMISSION_FACTOR["GasCCS"]) capture_factor["BioCCS"] = (EMISSION_FACTOR["Biomass"] * (1 + energy_penalty) - EMISSION_FACTOR["BioCCS"]) # %% DISCOUNT_RATE = 0.06 START_CARBON_PRICE = 0
"BioCCS": 0 } for y in range(2031, 2051): additions.loc[y] = increment #%% Old plant retirement program plant_life = pd.Series({ "Coal": 40, "Gas": 25, "Oil": 30, "BigHydro": 100, "SmallHydro": 60, "Biomass": 25, "Wind": 20, "Solar": 25, "CoalCCS": 40, "GasCCS": 25, "BioCCS": 25, "PumpedStorage": 100, "Import": 100 }) retirement = pd.DataFrame() for tech in plant_life.index: retirement[tech] = additions[tech].shift(plant_life[tech]) retirement.fillna(0, inplace=True)
def as_zero(fuel, _): """Return a time series of zero.""" show(fuel + " set as zero for all years") return pd.Series(0, index=years, name=fuel)
# and was built at a cost of 413 million yuan (53 million U.S. dollars). # ==> # 10^12 Wh / 8760 = 114 MW # 53 / 114 = 0.465 $/W = 465 $ per kW # # # http://news.xinhuanet.com/english/2017-04/19/c_136220293.htm # PREY VENG, Cambodia, April 19 (Xinhua) : The 160-km project... line # is capable of transmitting 150 megawatts (MW) electric power # at the cost of 75 million U.S. dollars # ==> # 500 $ per kW construction_cost_start_year_import = 500 construction_cost["Import"] = pd.Series(construction_cost_start_year_import, index=years, name="Import") show("Overnight construction costs, $/kW ", start_year) show(construction_cost.loc[start_year].round()) show() show("Trends in overnight construction costs, $/kW/yr", start_year, "-", end_year) show(construction_cost.diff().loc[start_year].round(2)) show() show("Overnight construction costs, $/kW") show(construction_cost[sources].round()) # %% Fixed operating costs
# Convert all other Gas capacity to Gas CCS on 2035 - 2050 retrofit_rate_gas = ( (baseline.capacities.at[END_YEAR, "Gas"] - PILOT1_SIZE - PILOT2_SIZE - additions.loc[RETROFIT_PERIOD, "Gas"].sum()) / len(RETROFIT_PERIOD)) retirement.loc[RETROFIT_PERIOD, "Gas"] += retrofit_rate_gas additions.loc[RETROFIT_PERIOD, "GasCCS"] = retrofit_rate_gas # Install new Gas CCS plants instead of simple Gas additions.loc[RETROFIT_PERIOD, "GasCCS"] += additions.loc[RETROFIT_PERIOD, "Gas"] additions.loc[RETROFIT_PERIOD, "Gas"] = 0 # Ramp up some BioCCS, quadratically BIOCCS_TREND = 10 # The increase of annual capacity installed (MW / yr) bioCCS_2050 = BIOCCS_TREND * len(RETROFIT_PERIOD) bioCCS_ramp = pd.Series(range(0, bioCCS_2050, BIOCCS_TREND), RETROFIT_PERIOD) additions.loc[RETROFIT_PERIOD, "BioCCS"] = bioCCS_ramp # Save a bit on Gas CCS, keeping the END_YEAR generation unchanged savedGasCCS = (bioCCS_ramp * baseline.capacity_factor.at[END_YEAR, "BioCCS"] / baseline.capacity_factor.at[END_YEAR, "GasCCS"]) additions.loc[RETROFIT_PERIOD, "GasCCS"] -= savedGasCCS withCCS = Plan(additions, retirement[technologies], baseline.capacity_factor, baseline.net_import) withCCS.__doc__ = "With CCS" if __name__ == '__main__': if (len(sys.argv) == 2) and (sys.argv[1] == "summarize"): withCCS.summarize() if (len(sys.argv) == 3) and (sys.argv[1] == "plot"):
# Convert all other Gas capacity to Gas CCS on 2035 - 2050 retrofit_rate_gas = ( (baseline.capacities.at[end_year, "Gas"] - pilot1_size - pilot2_size - additions.loc[retrofit_period, "Gas"].sum()) / len(retrofit_period)) retirement.loc[retrofit_period, "Gas"] += retrofit_rate_gas additions.loc[retrofit_period, "GasCCS"] = retrofit_rate_gas # Install new Gas CCS plants instead of simple Gas additions.loc[retrofit_period, "GasCCS"] += additions.loc[retrofit_period, "Gas"] additions.loc[retrofit_period, "Gas"] = 0 # Ramp up some BioCCS, quadratically bioCCS_trend = 10 # The increase of annual capacity installed (MW / yr) bioCCS_2050 = bioCCS_trend * len(retrofit_period) bioCCS_ramp = pd.Series(range(0, bioCCS_2050, bioCCS_trend), retrofit_period) additions.loc[retrofit_period, "BioCCS"] = bioCCS_ramp # Save a bit on Gas CCS, keeping the end_year generation unchanged savedGasCCS = (bioCCS_ramp * baseline.capacity_factor.at[end_year, "BioCCS"] / baseline.capacity_factor.at[end_year, "GasCCS"]) additions.loc[retrofit_period, "GasCCS"] -= savedGasCCS withCCS = PowerPlan(additions, retirement[technologies], baseline.capacity_factor, baseline.net_import) withCCS.__doc__ = "With CCS" if __name__ == '__main__': if (len(sys.argv) == 2) and (sys.argv[1] == "summarize"): withCCS.summarize() if (len(sys.argv) == 3) and (sys.argv[1] == "plot"):
CO2_captured = CO2_produced - CO2_emitted CO2_emitted = emission_factor_withCCS * production CO2_produced = CO2_factor_of_heat * heat_used CO2_produced = CO2_factor_of_heat * production * heat_rate_CCS CO2_produced = CO2_factor_of_heat * production * heat_rate_noCCS * (1 + energy_penalty) CO2_produced = production * emission_factor_noCCS * (1 + energy_penalty) CO2_captured = production * capture_factor capture_factor = emission_factor_noCCS * (1 + energy_penalty) - emission_factor_withCCS """ capture_factor = pd.DataFrame(index=years) for fuel in sources: capture_factor[fuel] = pd.Series(0, index=years) # gCO2/ kWh capture_factor["CoalCCS"] = (emission_factor["Coal"] * (1 + energy_penalty) - emission_factor["CoalCCS"]) capture_factor["GasCCS"] = (emission_factor["Gas"] * (1 + energy_penalty) - emission_factor["GasCCS"]) capture_factor["BioCCS"] = (emission_factor["Biomass"] * (1 + energy_penalty) - emission_factor["BioCCS"]) #%% discount_rate = 0.06 start_carbon_price = 0
Source : IPCC SRREN Methodology Annex II, Methodology Lead Authors: William Moomaw (USA), Peter Burgherr (Switzerland), Garvin Heath (USA), Manfred Lenzen (Australia, Germany), John Nyboer (Canada), Aviel Verbruggen (Belgium) Table A.II.4 page 982 "Aggregated results of literature review of LCAs of GHG emissions from electricity generation technologies (g CO2eq/kWh)" Median of the literature reviewed for Coal to Solar. (Min + Max)/2 for CCS technologies """ from init import pd EMISSION_FACTOR = pd.Series({ "Coal": 1001, "Gas": 469, "Oil": 840, "BigHydro": 4, "SmallHydro": 4, "Biomass": 18, "Wind": 12, "Solar": 46, "CoalCCS": (98 + 396) / 2, "GasCCS": (65 + 245) / 2, "BioCCS": (-1368 + (-594)) / 2 }) # gCO2eq / kWh #Assumption: VN imports from China and Lao EMISSION_FACTOR["Import"] = 0.5 * EMISSION_FACTOR[ "Coal"] + 0.5 * EMISSION_FACTOR["BigHydro"]