User guide

Generalization

Though cerf is demonstrated for the conterminous United States (CONUS), the package could easily be used in research ranging from regional to global analysis.

cerf requires the following inputs to be able to operate:

  • A shapefile of substations as points. The substation file must contain a field defining the minimum voltage per substation named “min_volt”.

  • A shapefile of gas pipelines as polylines if siting gas technologies.

  • A raster containing region IDs. Each grid cell has the value of its parent region. Currently, this is demonstrated using US states, though this could be generalized to any region/country/locale identifier matching what the electricity expansion plan provides.

  • A raster containing locational marginal pricing (LMP) zone IDs. Each grid cell has the ID of its LMP zones. These zones are representative of the nodal structure of the underlying model or software that produces the LMPs. Production cost models to generate this value are not US-specific and this could be generated from any number of open-source and/or commercial products.

  • A file of LMPs per zone (corresponding to the aforementioned raster) for each 8760 hour. Again, the source model or dataset that these are generated from does not have to be US-specific.

  • An electricity capacity expansion plan and its accompanying technology-specific information (e.g., variable O&M, fuel price, etc.). For the CONUS, we use the 50 US-state version of GCAM. However, GCAM is a global model and can produce this data for each of its regions.

  • Both the region-abbrev_to_region-name.yml and the region-name_to_region-id.yml files can be replaced with regional information.

  • Other variable information which is able to be modified per run, are the assumed interconnection costs per km to a substation KV class and the cost per km to connect to a gas pipeline if applicable.

  • Lastly, are the suitability rasters which can be composed of any number of locally-relevant exclusion criteria (e.g., protected area, critical habitat, etc.) per technology being sited in the expansion plan.

Let us know if you are using cerf in your research in our discussion thread!

Setting up a cerf run

The following with indroduce you to the input data required by cerf and how to set up a configuration file to run cerf.

Configuration file setup

The cerf package utilizes a YAML configuration file customized by the user with project level and technology-specific settings, an electricity technology capacity expansion plan, and LMP zone data for each year intended to model. cerf comes equipped with prebuilt configuration files for years 2010 through 2050 to provide an illustrative example. Each example configuration file can be viewed using the following:

import cerf

sample_config = cerf.load_sample_config(yr=2010)

The following are the required key, values if your wish to construct your own configuration files:

settings

These are required values for project-level settings.

Name

Description

Unit

Type

run_year

Target year to run in YYYY format

year

int

output_directory

Directory to write the output data to

NA

str

randomize

Randomize selection of a site for a technology when
NLC values are equal. The first pass is always
random but setting randomize to False and passing
a seed value will ensure that runs are reproducible

NA

str

seed_value

If randomize is False; set a seed value for
reproducibility; the default is 0

NA

int

The following is an example implementation in the YAML configuration file:

settings:

    run_year: 2010
    output_directory: <your output directory>
    randomize: False
    seed_value: 0

technology

These are technology-specific settings.

Name

Description

Unit

Type

<tech id number>

This is an integer ID key given to the
technology for reference purposes. This
ID should match the corresponding
technology in the electricity technology
expansion plan.

NA

int

tech_name

Name of the technology

NA

str

lifetime_yrs

Asset lifetime used in calculating
annuity factor

n_years

int

operational_life_yrs

A separate parameter to allow for early
retirement of power plants (i.e., not
operating to their full expected life) and
is set as the number of years after
siting that the plant gets retired.

n_years

int

capacity_factor_fraction

Defined as average annual power generated
divided by the potential output if the
plant operated at its rated capacity for a
year

fraction

float

variable_om_esc_rate_fraction

Escalation rate of variable cost

fraction

float

fuel_price_esc_rate_fraction

Escalation rate of fuel

fraction

float

unit_size_mw

The size of the expected power plant

MW

float

variable_om_usd_per_mwh

Variable operation and maintenance costs
of yearly capacity use

$/MWh

float

heat_rate_btu_per_kWh

Amount of energy used by a power plant to
generate one kilowatt-hour of electricity

Btu/kWh

float

fuel_price_usd_per_mmbtu

Cost of fuel per unit

$/MMbtu

float

carbon_capture_rate_fraction

Rate of carbon capture

fraction

float

fuel_co2_content_tons_per_btu

CO2 content of the fuel and the heat rate
of the technology

tons/Btu

float

discount_rate

The time value of money in real terms

fraction

float

carbon_tax_esc_rate_fraction

Escalation rate of carbon

fraction

float

carbon_tax_usd_per_ton

The fee imposed on the burning of
carbon-based fuels

$/ton

float

buffer_in_km

Buffer around the site to apply in
kilometers which becomes unsuitable for
other sites after siting

n_km

int

require_pipelines

If the technology is gas related pipelines
will be used when calculating the
interconnection cost

NA

bool

suitability_raster_file

Full path with file name and extension to
the accompanying suitability raster file

NA

str

The following is an example implementation in the YAML configuration file:

technology:

    9:
        tech_name: biomass
        lifetime_yrs: 60
        operational_life_yrs: 60
        capacity_factor_fraction: 0.6090000000000005
        variable_om_esc_rate_fraction: -0.00398993418629034
        fuel_price_esc_rate_fraction: 0.0
        unit_size_mw: 80
        variable_om: 11.68495803744351
        heat_rate_btu_per_kWh: 15117.64999999997
        fuel_price_usd_per_mmbtu: 0.0
        carbon_capture_rate_fraction: 0.0
        fuel_co2_content_tons_per_btu: 0.3035999999999996
        discount_rate: 0.05
        carbon_tax_esc_rate_fraction: 0.0
        carbon_tax_usd_per_ton: 0.0
        buffer_in_km: 5
        require_pipelines: False
        suitability_raster_file: <path to file>

expansion_plan

These are technology-specific settings.

Name

Description

Unit

Type

<region name>

Name key of region in all lower case with
underscore separation

NA

str

<tech id key>

Technology ID key matching what is in the
technology section (e.g. 9)

NA

int

tech_name

Name of the technology matching the name
in the technology section

NA

str

n_sites

Number of sites desired

n_sites

int

The following is an example implementation in the YAML configuration file:

expansion_plan:

    arizona:
        9:
            tech_name: biomass
            n_sites: 2

lmp_zones

These are the lmp zones data representing the linkage between each grid and technology and their locational marginal price (LMP).

Name

Description

Unit

Type

lmp_zone_raster_file

Full path with file name and extension to
the lmp zoness raster file

NA

str

lmp_zone_raster_nodata_value

No data value in the lmp zones raster

NA

float

lmp_hourly_data_file

LMP CSV file containing 8760 LMP per zone
where columns are each zone with a numeric
zone ID header that corresponds with the
zones represented in the
lmp_zone_raster_file found in the
lmp_zones section and an
additional hour column named hour
holding the hour of each record

$/MWh

str

The following is an example implementation in the YAML configuration file:

lmp_zones:

    lmp_zone_raster_file: <path to zone raster>
    lmp_zone_raster_nodata_value: 255
    lmp_hourly_data_file: <path to data file>

The cerf package comes equipped with a sample lmp zoness raster file and a sample hourly (8760) locational marginal price file for illustrative purposes only.

You can take a look at the lmp zoness raster file by running:

import cerf

lmp_zone_file = cerf.sample_lmp_zones_raster_file()

You can also view the sample hourly locational marginal price file as a Pandas DataFrame using:

import cerf

df = cerf.get_sample_lmp_data()

infrastructure

These are the electricity transmission and gas pipeline infrastructure data.

Name

Description

Unit

Type

substation_file

Full path with file name and extension to
he input substations shapefile. If
null cerf will use the default
data stored in the package.

NA

str

pipeline_file

Full path with file name and extension to
he input pipelines shapefile. If null
CERF will use the default data stored in
the package.

NA

str

transmission_costs_file

A YAML file containing the costs of
connection per km to a substation having
a certain minimum voltage range. Default
is to load from the defualt
‘costs_per_kv_substation.yml’ file
by specifying null

NA

str

pipeline_costs_file

A YAML file containing the costs of
connection per km to a gas pipeline.
Default is to load from the default
‘costs_gas_pipeline.yml’ file
by specifying null

NA

str

output_rasterized_file

Write distance raster

NA

bool

output_dist_file

Write distance raster

NA

bool

output_alloc_file

Write allocation file

NA

bool

output_cost_file

Write cost file

NA

bool

output_dir

If writing files, specify an out directory

NA

bool

interconnection_cost_file

Full path with the file name and extension
to a preprocessed interconnection cost
NPY file that has been previously written.
If null, interconnection costs will be
calculated.

NA

str

The following is an example implementation in the YAML configuration file:

infrastructure:

    substation_file: <path to substation shapefile>
    transmission_costs_file: <path to the yaml file>
    pipeline_file: <path to the pipeline file>
    output_rasterized_file: false
    output_dist_file: false
    output_alloc_file: false
    output_cost_file: false

You can view the built-in costs per kV to connect to a substation using:

import cerf

costs_dict = cerf.costs_per_kv_substation()

Preparing suitability rasters

The cerf package comes equipped with sample suitability data but you can build your on as well.

You can see which suitability rasters are available in the cerf package by running the following after installing the package data:

import cerf

cerf.list_available_suitability_files()

The sample rasters for spatial suitability at a resolution of 1km over the CONUS use the following format. Suitability rasters can be prepared using any GIS.

Attribute

Description

Number of columns
Number of rows

4693, 2999

Coordinate system

PROJCS[“USA_Contiguous_Albers_Equal_Area_Conic”,
GEOGCS[“GCS_North_American_1983”,
DATUM[“North_American_Datum_1983”,
SPHEROID[“GRS_1980”,6378137.0,298.257222101]],
PRIMEM[“Greenwich”,0.0],
UNIT[“Degree”,0.0174532925199433]],
PROJECTION[“Albers_Conic_Equal_Area”],
PARAMETER[“false_easting”,0.0],
PARAMETER[“false_northing”,0.0],
PARAMETER[“longitude_of_center”,-96.0],
PARAMETER[“standard_parallel_1”,29.5],
PARAMETER[“standard_parallel_2”,45.5],
PARAMETER[“latitude_of_center”,37.5],
UNIT[“Meters”,1.0]]

Origin

(-2405552.835500000044703, 1609934.799499999964610)

Pixel Size

(1000, -1000)

Upper Left

(-2405552.836, 1609934.799)

Lower Left

(-2405552.836, -1389065.201)

Upper Right

(2287447.164, 1609934.799)

Lower Right

(2287447.164, -1389065.201)

Center

(-59052.836, 110434.799)

Type

Byte

Locational Marginal Price

Locational Marginal Pricing (LMP) represents the cost of making and delivering electricity over an interconnected network of service nodes. LMPs are delivered on an hourly basis (8760 hours for the year) and help us to understand aspects of generation and congestion costs relative to the supply and demand of electricity when considering existing transmission infrastructure. LMPs are a also driven by factors such as the cost of fuel which cerf also takes into account when calculating a power plants Net Operating Value. When working with a scenario-driven grid operations model to evaluate the future evolution of the electricity system, cerf can ingest LMPs, return the sited generation per service area for the time step, and then continue this iteration through all future years to provide a harmonized view how the electricity system may respond to stressors in the future.

cerf was designed to ingest a single CSV file of LMPs per service area for each of the 8760 hours in a year where LMPs are in units $/MWh. Mean LMPs representing annual trends are then calculated over the time period corresponding to each technology’s capacity factor using the following logic:

FOR each service area AND technology

  SORT LMP 8760 values descending and rank 1..8760 where 1 is the largest LMP value;

  IF the capacity factor is == 1.0:
    MEAN of all values;

  ELSE IF the capacity factor is >= 0.5:
    MEAN of values starting in the rank position
    CEILING(8760 * (1 - capacity factor)) through 8760;

  ELSE IF the 0.0 < capacity factor < 0.5:
    MEAN of values starting in the rank position 1 through
    CEILING(8760 * (1 - capacity factor));

  ELSE:
    FAIL;

Note

cerf comes with an LMP dataset for illustrative purposes only which can be accessed using the get_sample_lmp_file() function. The service areas in this file correspond with the sample lmp zoness raster file in the cerf package which defines the service area ID for each grid cell in the CONUS. This raster file can also be accessed using sample_lmp_zones_raster_file() function.

Tutorials

cerf quickstarter

Load packages

import cerf

Install package data

NOTE: The package data will require approximately 195 MB of storage.

Ensure that you have installed the package data using:

cerf.install_package_data()

Conduct a run with CERF

We will be exploring the main functionality of the cerf package using our our example data which is meant for illustrative purposes only. cerf runs using a single YAML configuration file that contains project and technology-specific settings, an electricity capacity expansion plan, and LMP zones pricing data which is described in detail in the docs here. Expansion plans and technology data are generally generated by models such as GCAM which capture multi-sector dynamics that represent alternate futures based on scenario assumptions for socioeconomics, radiative forcing, etc. The cerf package also comes equipped with power plant siting suitability data at a 1-km resolution over the CONUS, publically available data from EIA and HIFLD for transmission and pipeline infrastructure, and generic 8760 locational marginal pricing similar to what you could model using your prefered grid operations model.

Run cerf to site power plants in an expansion plan for a single year for the CONUS

# sample year
yr = 2030

# load the sample configuration file path for the target year
config_file = cerf.config_file(yr)

# run the configuration for the target year and return a data frame
result_df = cerf.run(config_file, write_output=False)
2021-08-24 11:44:03,734 - root - INFO - Starting CERF model
2021-08-24 11:44:03,956 - root - INFO - Staging data...
2021-08-24 11:44:04,168 - root - INFO - Using 'zones_raster_file':  /Users/d3y010/repos/github/cerf/cerf/data/lmp_zones_1km.img
2021-08-24 11:44:04,203 - root - INFO - Processing locational marginal pricing (LMP)
2021-08-24 11:44:04,203 - root - INFO - Using LMP from default illustrative package data:  /Users/d3y010/repos/github/cerf/cerf/data/illustrative_lmp_8760-per-zone_dollars-per-mwh.zip
2021-08-24 11:44:13,798 - root - INFO - Calculating interconnection costs (IC)
2021-08-24 11:44:13,798 - root - INFO - Using default substation costs from file: /Users/d3y010/repos/github/cerf/cerf/data/costs_per_kv_substation.yml
2021-08-24 11:44:13,802 - root - INFO - Using default substation file: /Users/d3y010/repos/github/cerf/cerf/data/hifld_substations_conus_albers.zip
2021-08-24 11:44:21,669 - root - INFO - Using default gas pipeline file:  /Users/d3y010/repos/github/cerf/cerf/data/eia_natural_gas_pipelines_conus_albers.zip
2021-08-24 11:44:22,938 - root - INFO - Using gas pipeline costs from default file:  /Users/d3y010/repos/github/cerf/cerf/data/costs_gas_pipeline.yml
2021-08-24 11:44:29,649 - root - INFO - Calculating net operational cost (NOV)
2021-08-24 11:44:30,783 - root - INFO - Calculating net locational cost (NLC)
2021-08-24 11:44:31,325 - root - INFO - Building suitability array
2021-08-24 11:44:31,749 - root - INFO - Using suitability file for 'biomass_conv_wo_ccs':  /Users/d3y010/repos/github/cerf/cerf/data/suitability_biomass.sdat
2021-08-24 11:44:31,789 - root - INFO - Using suitability file for 'biomass_igcc_wo_ccs':  /Users/d3y010/repos/github/cerf/cerf/data/suitability_biomass_igcc.sdat
2021-08-24 11:44:31,825 - root - INFO - Using suitability file for 'coal_conv_pul_wo_ccs':  /Users/d3y010/repos/github/cerf/cerf/data/suitability_coal.sdat
2021-08-24 11:44:31,852 - root - INFO - Using suitability file for 'gas_cc_wo_ccs':  /Users/d3y010/repos/github/cerf/cerf/data/suitability_gas_cc.sdat
2021-08-24 11:44:31,881 - root - INFO - Using suitability file for 'gas_cc_w_ccs':  /Users/d3y010/repos/github/cerf/cerf/data/suitability_gas_cc_ccs.sdat
2021-08-24 11:44:31,908 - root - INFO - Using suitability file for 'nuclear_gen_ii':  /Users/d3y010/repos/github/cerf/cerf/data/suitability_nuclear.sdat
2021-08-24 11:44:31,935 - root - INFO - Using suitability file for 'nuclear_gen_iii':  /Users/d3y010/repos/github/cerf/cerf/data/suitability_nuclear.sdat
2021-08-24 11:44:31,963 - root - INFO - Using suitability file for 'oil_ct_wo_ccs':  /Users/d3y010/repos/github/cerf/cerf/data/suitability_oil_baseload.sdat
2021-08-24 11:44:31,989 - root - INFO - Using suitability file for 'solar_csp':  /Users/d3y010/repos/github/cerf/cerf/data/suitability_solar.sdat
2021-08-24 11:44:32,015 - root - INFO - Using suitability file for 'solar_pv_non_dist':  /Users/d3y010/repos/github/cerf/cerf/data/suitability_solar.sdat
2021-08-24 11:44:32,042 - root - INFO - Using suitability file for 'wind_onshore':  /Users/d3y010/repos/github/cerf/cerf/data/suitability_wind.sdat
2021-08-24 11:44:32,069 - root - INFO - Staged data in 28.1118519 seconds
2021-08-24 11:44:33,086 - root - INFO - Processed alabama in 1.0166159 seconds
2021-08-24 11:44:34,387 - root - INFO - Processed arizona in 1.3004961 seconds
2021-08-24 11:44:34,920 - root - INFO - Processed arkansas in 0.531682 seconds
2021-08-24 11:44:39,114 - root - INFO - Processed california in 4.19344 seconds
2021-08-24 11:44:39,809 - root - INFO - Processed colorado in 0.6944351 seconds
2021-08-24 11:44:39,956 - root - INFO - Processed connecticut in 0.1455598 seconds
2021-08-24 11:44:40,040 - root - INFO - Processed delaware in 0.083498 seconds
2021-08-24 11:44:40,114 - root - INFO - Processed district_of_columbia in 0.0735919 seconds
2021-08-24 11:44:41,768 - root - INFO - Processed florida in 1.6528592 seconds
2021-08-24 11:44:42,681 - root - INFO - Processed georgia in 0.9123399 seconds
2021-08-24 11:44:43,257 - root - INFO - Processed idaho in 0.5753481 seconds
2021-08-24 11:44:44,108 - root - INFO - Processed illinois in 0.8507626 seconds
2021-08-24 11:44:44,496 - root - INFO - Processed indiana in 0.3873999 seconds
2021-08-24 11:44:45,108 - root - INFO - Processed iowa in 0.610285 seconds
2021-08-24 11:44:45,625 - root - INFO - Processed kansas in 0.5162001 seconds
2021-08-24 11:44:46,092 - root - INFO - Processed kentucky in 0.46629 seconds
2021-08-24 11:44:46,929 - root - INFO - Processed louisiana in 0.8366458 seconds
2021-08-24 11:44:47,207 - root - INFO - Processed maine in 0.276648 seconds
2021-08-24 11:44:47,427 - root - INFO - Processed maryland in 0.2200139 seconds
2021-08-24 11:44:47,603 - root - INFO - Processed massachusetts in 0.1754241 seconds
2021-08-24 11:44:48,601 - root - INFO - Processed michigan in 0.9966919 seconds
2021-08-24 11:44:49,403 - root - INFO - Processed minnesota in 0.8013589 seconds
2021-08-24 11:44:50,051 - root - INFO - Processed mississippi in 0.6468239 seconds
2021-08-24 11:44:50,769 - root - INFO - Processed missouri in 0.7176321 seconds
2021-08-24 11:44:51,607 - root - INFO - Processed montana in 0.83709 seconds
2021-08-24 11:44:52,010 - root - INFO - Processed nebraska in 0.4028261 seconds
2021-08-24 11:44:53,065 - root - INFO - Processed nevada in 1.0537767 seconds
2021-08-24 11:44:53,235 - root - INFO - Processed new_hampshire in 0.169647 seconds
2021-08-24 11:44:53,436 - root - INFO - Processed new_jersey in 0.1997998 seconds
2021-08-24 11:44:54,095 - root - INFO - Processed new_mexico in 0.659168 seconds
2021-08-24 11:44:55,054 - root - INFO - Processed new_york in 0.9580491 seconds
2021-08-24 11:44:55,747 - root - INFO - Processed north_carolina in 0.6923168 seconds
2021-08-24 11:44:56,122 - root - INFO - Processed north_dakota in 0.3739688 seconds
2021-08-24 11:44:56,679 - root - INFO - Processed ohio in 0.5559881 seconds
2021-08-24 11:44:57,555 - root - INFO - Processed oklahoma in 0.8756032 seconds
2021-08-24 11:44:58,328 - root - INFO - Processed oregon in 0.7727861 seconds
2021-08-24 11:44:59,067 - root - INFO - Processed pennsylvania in 0.7384419 seconds
2021-08-24 11:44:59,145 - root - INFO - Processed rhode_island in 0.0770929 seconds
2021-08-24 11:44:59,585 - root - INFO - Processed south_carolina in 0.438771 seconds
2021-08-24 11:44:59,922 - root - INFO - Processed south_dakota in 0.3369012 seconds
2021-08-24 11:45:00,338 - root - INFO - Processed tennessee in 0.4145651 seconds
2021-08-24 11:45:12,257 - root - INFO - Processed texas in 11.9182241 seconds
2021-08-24 11:45:12,893 - root - INFO - Processed utah in 0.6355641 seconds
2021-08-24 11:45:13,009 - root - INFO - Processed vermont in 0.1157441 seconds
2021-08-24 11:45:13,649 - root - INFO - Processed virginia in 0.63941 seconds
2021-08-24 11:45:14,111 - root - INFO - Processed washington in 0.4608808 seconds
2021-08-24 11:45:14,389 - root - INFO - Processed west_virginia in 0.2771189 seconds
2021-08-24 11:45:14,896 - root - INFO - Processed wisconsin in 0.5063529 seconds
2021-08-24 11:45:15,473 - root - INFO - Processed wyoming in 0.5768282 seconds
2021-08-24 11:45:15,474 - root - INFO - All regions processed in 43.4045889 seconds.
2021-08-24 11:45:15,475 - root - INFO - Aggregating outputs...
2021-08-24 11:45:15,861 - root - INFO - CERF model run completed in 72.1272678 seconds

Results are returned as a Pandas DataFrame

Each record is a sited power plant having a geographic location and other siting attributes. Reminder: cerf uses the USA_Contiguous_Albers_Equal_Area_Conic projected coordinate reference system in its CONUS example data, so the xcoord and ycoord are relative to that projection.

result_df.head()

Run cerf to site power plants in an expansion plan for multiple years for the CONUS

This exercise demonstrates how to inherit sites from a previous year’s results and keep them in the mix if they have not yet reached retirement. If this is done in cerf, users should ensure that their expansion plan is only for new vintage each timestep.

import cerf

# process year 2010, 2030, and 2050
for index, yr in enumerate([2010, 2030, 2050]):

    print(f"\nProcessing year:  {yr}")

    # load the sample configuration file path for the target year
    config_file = cerf.config_file(yr)

    # do not intialize the run with previously sited data if it is the first time step
    if index == 0:
        result_df = cerf.run(config_file, write_output=False)

    else:
        result_df = cerf.run(config_file, write_output=False, initialize_site_data=result_df)

Explore the results that account for retirement

Since we inherited the each year, and we are only siting new vintage per year, we see power plants from multiple technlogies until they reach their retirement age. We can narrow in on biomass power plants in Virginia to see this:

result_df.loc[(result_df['region_name'] == 'virginia') & (result_df['tech_id'] == 9)]

Plot the output

cerf.plot_siting(result_df)
_images/quickstart_plot.png

Running the quickstarter locally

You can download the cerf quickstarter Jupyter notebook here: cerf quickstarter

This will allow you to run the tutorial interactively on your local computer. Installation instructions for installing Jupyter software can be found here.

Once you have Jupyter up-and-running, make sure you install cerf and its package data by running:

python3 -m pip install cerf

python3 -c 'import cerf; cerf.install_package_data()'

where, python3 would be the instance of Python that you installed Jupyter on. Now you are ready to explore cerf!

Fundamental equations and concepts

The following are the building blocks of how cerf sites power plants.

Net Operating Value

The Net Operating Value is the difference between the locational marginal value of the energy generated by a technology and its operating costs. The locational marginal value is a function of the plant’s capacity factor, the average locational marginal price (LMP) for that capacity factor in the zone that encompasses the grid cell, and the plant’s generation. The average LMP for each zone/capacity factor is calculated from a grid operation model output as the average of the hours corresponding to that capacity factor (e.g., for a 10% capacity factor, the LMP is calculated based on the top 10% of LMP values). The operating costs are determined by the plant’s generation, heat rate, fuel cost, variable O&M, carbon tax, and carbon emissions–if there is a carbon tax in the expansion plan scenario being processed.

Net operating value (NOV)

NOV = G(LMP - OC)

where, NOV is Net Operating Value in $/yr; G is electricity generation in MWh/yr; LMP is locational marginal price in $/MWh; OC are operating costs in $/MWh.

Generation (G)

G = U * CF * HPY

where, U is the unit size of a power plant in MW; CF is the capacity factor of the power plant; HPY is the number of hours in a year. Both unit size and capacity factor are input variables to cerf.

Levelization factor (LFi)

k_i = \frac{1 + l_i}{1 + d}

LF_i = k_i(1-k_i^n) * \frac{AF}{1-k_i}

where, lfuel is an escalation rate as a fraction; d is the real annual discount rate as a fraction; n is the asset lifetime in years; and AF is the annuity factor. All escalation rates are input variables to cerf.

Annuity factor (AF)

AF = \frac{d(1 + d)^n}{(1 + d)^n - 1}

where, d is the real annual discount rate as a fraction and n is the asset lifetime in years.

Locational marginal price (LMP)

LMP_{lev} = LMP * LF_{fuel}

where, LMP is the locational marginal price (LMP) in $/MWh and LFfuel is the levelization factor of fuel. LMP is also an input to cerf and is described in full in the Locational Marginal Price section.

Operating cost (OC)

OC = \bigg(HR * \bigg(\frac{FP}{1000}\bigg) * LF_{fuel}\bigg) + \bigg(VOM * LF_{vom}\bigg) + \bigg(\bigg(\frac{CT * CO2 * HR * LF_{carbon}}{1000000}\bigg) * \bigg(1 - CCR\bigg)\bigg)

where, HR is heat rate in Btu/kWh; FP is fuel price which cerf takes in as $/GJ but it gets converted to $/MBtu in the model; VOM is the variable operation and maintenance costs of yearly capacity use in $/MWh; LFvom is the levelization factor of variable O&M; CT is the carbon tax in $/ton; CO2 is the CO2 content of the fuel taken as an input in units tons/MWh but gets converted to tons/Btu in the model; LFcarbon is the levelization factor for carbon as a fraction; and CCR is the carbon capture rate as a fraction. All variables are inputs to the cerf model.

Interconnection Cost

Interconnection cost is the sum of the transmission interconnection cost and the gas pipeline interconnection cost (if a gas-fired technology is being evaluated) at each grid cell. cerf calculates the distances to the nearest substation with the minimum required voltage rating and to the nearest gas pipeline with the minimum required diameter for each suitable grid cell. It then applies distance- and voltage-based capital costs to estimate the total cost for the new plant to connect to the grid. This is calculated as:

IC = (D_{elec} * C_{elec} * AF) + (D_{gas} * C_{gas} * AF)

where, IC is Interconnection Cost in $/yr; Delec is the distance to the nearest suitable electricity transmission infrastructure (e.g., substation) in kilometers; Celec is the electric grid interconnection captial cost in thous$/km; Dgas is the distance to the nearest suitable gas pipeline in kilometers; Cgas is the gas interconnection capital cost in thous$/km and AF is the annuity factor.

The annuity factor (AF) is calculated as:

AF = \frac{d(1 + d)^n}{(1 + d)^n - 1}

where, d is the real annual discount rate as a fraction and n is the asset lifetime in years.

Net Locational Cost

Net Locational Cost (NLC) is used to compete power plant technologies per grid cell based on the least expensive option to site. NLC is calculated by subtracting the Net Operating Value (NOV) of the proposed power plant from the cost of its interconnection (IC) to the grid to represent the potential deployment value. Both the NOV parameter which incorporates many technology-specific values such as variable operations and maintenance costs, carbon price, heat rate, etc. and the interconnection cost parameter used for both electricity transmission and gas pipelines have variables that are accessible to the user for modification per time step.

NLC is calculated as:

NLC = IC - NOV

where, NLC is in $/yr; IC is interconnection cost in $/yr; and NOV is in $/yr.

Competition algorithm

Technology competition algorithm for CERF.

Grid cell level net locational cost (NLC) per technology and an electricity technology capacity expansion plan are used to compete technologies against each other to see which will win the grid cell. The technology that wins the grid cell is then sited until no further winning cells exist. Once sited, the location of the winning technology’s grid cell, along with its buffer, are no longer available for siting. The competition array is recalculated after all technologies have passed through an iteration. This process is repeated until there are either no cells left to site or there are no more power plants left to satisfy the expansion plan for any technology. For technologies that have the same NLC value in multiple grid cells that win the competition, random selection is available by default. If the user wishes to have the outcomes be repeatable, the randomizer can be set to False and a random seed set.

Key outputs

The following are the outputs and their descriptions from the Pandas DataFrame that is generated when calling run() to site power plant for all regions in the CONUS for all technologies:

Name

Description

Units

region_name

Name of region

NA

tech_id

Technology ID

NA

tech_name

Technology name

NA

unit_size_mw

Power plant unit size

MW

xcoord

X coordinate in the default CRS

meters

ycoord

Y coordinate in the default CRS

meters

index

Index position in the flattend 2D array

NA

buffer_in_km

Exclusion buffer around site

km

sited_year

Year of siting

year

retirement_year

Year of retirement

year

lmp_zone

LMP zone ID

NA

locational_marginal_price_usd_per_mwh

See Locational marginal price (LMP)

$/MWh

generation_mwh_per_year

See Generation (G)

MWh/yr

operating_cost_usd_per_year

See Operating cost (OC)

$/yr

net_operational_value

See Net Operating Value

$/yr

interconnection_cost

See Interconnection Cost

$/yr

net_locational_cost

See Net Locational Cost

$/yr

capacity_factor_fraction

Capacity factor

fraction

carbon_capture_rate_fraction

Carbon capture rate

fraction

fuel_co2_content_tons_per_btu

Fuel CO2 content

tons/Btu

fuel_price_usd_per_mmbtu

Fuel price

$/MMBtu

fuel_price_esc_rate_fraction

Fuel price escalation rate

fraction

heat_rate_btu_per_kWh

Heat rate

Btu/kWh

lifetime_yrs

Technology lifetime for annuity

years

operational_life_yrs

Operational lifetime for retirement

years

variable_om_usd_per_mwh

Variable operation and maintenance costs of yearly capacity use

$/mWh

variable_om_esc_rate_fraction

Variable operation and maintenance costs escalation rate

fraction

carbon_tax_usd_per_ton

Carbon tax

$/ton

carbon_tax_esc_rate_fraction

Carbon tax escalation rate

fraction