Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add column mapping for proposed multifuel table #3988

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
4 changes: 4 additions & 0 deletions docs/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ v2024.XX.x (2024-MM-DD)
New Data Coverage
^^^^^^^^^^^^^^^^^

EIA 860
~~~~~~~
* Added EIA 860 Multifuel data. See :issue:`3438` and :pr:`3946`.

Bug Fixes
^^^^^^^^^

Expand Down
87 changes: 87 additions & 0 deletions migrations/versions/bbd829448c4b_add_multifuel_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"""Add multifuel table

Revision ID: bbd829448c4b
Revises: 450d100cd30b
Create Date: 2025-01-17 14:36:41.966480

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'bbd829448c4b'
down_revision = '450d100cd30b'
branch_labels = None
depends_on = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('core_eia860__scd_generators_multifuel',
sa.Column('report_date', sa.Date(), nullable=False, comment='Date reported.'),
sa.Column('utility_id_eia', sa.Integer(), nullable=False, comment='The EIA Utility Identification number.'),
sa.Column('utility_name_eia', sa.Text(), nullable=True, comment='The name of the utility.'),
sa.Column('plant_id_eia', sa.Integer(), nullable=False, comment='The unique six-digit facility identification number, also called an ORISPL, assigned by the Energy Information Administration.'),
sa.Column('plant_name_eia', sa.Text(), nullable=True, comment='Plant name.'),
sa.Column('state', sa.Text(), nullable=True, comment='Two letter US state abbreviation.'),
sa.Column('county', sa.Text(), nullable=True, comment='County name.'),
sa.Column('generator_id', sa.Text(), nullable=False, comment='Generator ID is usually numeric, but sometimes includes letters. Make sure you treat it as a string!'),
sa.Column('operational_status_code', sa.Text(), nullable=True, comment='The operating status of the asset.'),
sa.Column('technology_description', sa.Text(), nullable=True, comment='High level description of the technology used by the generator to produce electricity.'),
sa.Column('prime_mover_code', sa.Text(), nullable=True, comment='Code for the type of prime mover (e.g. CT, CG)'),
sa.Column('sector_name_eia', sa.Text(), nullable=True, comment='EIA assigned sector name, corresponding to high level NAICS sector, designated by the primary purpose, regulatory status and plant-level combined heat and power status'),
sa.Column('sector_id_eia', sa.Integer(), nullable=True, comment='EIA assigned sector ID, corresponding to high level NAICS sector, designated by the primary purpose, regulatory status and plant-level combined heat and power status'),
sa.Column('capacity_mw', sa.Float(), nullable=True, comment='Total installed (nameplate) capacity, in megawatts.'),
sa.Column('summer_capacity_mw', sa.Float(), nullable=True, comment='The net summer capacity.'),
sa.Column('winter_capacity_mw', sa.Float(), nullable=True, comment='The net winter capacity.'),
sa.Column('current_planned_generator_operating_date', sa.Date(), nullable=True, comment='The most recently updated effective date on which the generator is scheduled to start operation'),
sa.Column('energy_source_code_1', sa.Text(), nullable=True, comment='The code representing the most predominant type of energy that fuels the generator.'),
sa.Column('energy_source_code_2', sa.Text(), nullable=True, comment='The code representing the second most predominant type of energy that fuels the generator'),
sa.Column('multiple_fuels', sa.Boolean(), nullable=True, comment='Can the generator burn multiple fuels?'),
sa.Column('cofire_fuels', sa.Boolean(), nullable=True, comment='Can the generator co-fire fuels?'),
sa.Column('cofire_energy_source_1', sa.Text(), nullable=True, comment='Type of fuel.'),
sa.Column('cofire_energy_source_2', sa.Text(), nullable=True, comment='Type of fuel.'),
sa.Column('cofire_energy_source_3', sa.Text(), nullable=True, comment='Type of fuel.'),
sa.Column('cofire_energy_source_4', sa.Text(), nullable=True, comment='Type of fuel.'),
sa.Column('cofire_energy_source_5', sa.Text(), nullable=True, comment='Type of fuel.'),
sa.Column('cofire_energy_source_6', sa.Text(), nullable=True, comment='Type of fuel.'),
sa.Column('switch_oil_gas', sa.Boolean(), nullable=True, comment='Indicates whether the generator switch between oil and natural gas.'),
sa.Column('can_switch_when_operating', sa.Boolean(), nullable=True, comment='Indicates whether the generator switches fuel while operating.'),
sa.Column('net_summer_capacity_with_natural_gas_mw', sa.Float(), nullable=True, comment='Summer capacity with natural gas.'),
sa.Column('net_summer_capacity_with_oil_mw', sa.Float(), nullable=True, comment='Summer capacity with oil.'),
sa.Column('net_winter_capacity_with_natural_gas_mw', sa.Float(), nullable=True, comment='Winter capacity with natural gas.'),
sa.Column('net_winter_capacity_with_oil_mw', sa.Float(), nullable=True, comment='Winter capacity with oil'),
sa.Column('has_factors_that_limit_switching', sa.Boolean(), nullable=True, comment='True if there are factors that limit switching.'),
sa.Column('has_storage_limits', sa.Boolean(), nullable=True, comment='True if there are storage limits'),
sa.Column('has_air_permit_limits', sa.Boolean(), nullable=True, comment='True if there are air permit limits'),
sa.Column('has_other_limits', sa.Boolean(), nullable=True, comment='True if there are other limits on the generator.'),
sa.Column('can_cofire_oil_and_gas', sa.Boolean(), nullable=True, comment='Can the generator co-fire oil and gas?'),
sa.Column('can_cofire_100_oil', sa.Boolean(), nullable=True, comment='Can the generator co-fire 100 oil?'),
sa.Column('max_oil_heat_input', sa.Float(), nullable=True, comment='TK'),
sa.Column('max_oil_output_mw', sa.Float(), nullable=True, comment='MW'),
sa.Column('can_fuel_switch', sa.Boolean(), nullable=True, comment='TK'),
sa.Column('time_to_switch', sa.Text(), nullable=True, comment='Time needed to switch between fuel sources'),
sa.Column('regulatory_limits', sa.Text(), nullable=True, comment='TK'),
sa.Column('fuel_switch_energy_source_1', sa.Text(), nullable=True, comment='TK'),
sa.Column('fuel_switch_energy_source_2', sa.Text(), nullable=True, comment='TK'),
sa.Column('fuel_switch_energy_source_3', sa.Text(), nullable=True, comment='TK'),
sa.Column('fuel_switch_energy_source_4', sa.Text(), nullable=True, comment='TK'),
sa.Column('fuel_switch_energy_source_5', sa.Text(), nullable=True, comment='TK'),
sa.Column('fuel_switch_energy_source_6', sa.Text(), nullable=True, comment='TK'),
sa.ForeignKeyConstraint(['energy_source_code_1'], ['core_eia__codes_energy_sources.code'], name=op.f('fk_core_eia860__scd_generators_multifuel_energy_source_code_1_core_eia__codes_energy_sources')),
sa.ForeignKeyConstraint(['energy_source_code_2'], ['core_eia__codes_energy_sources.code'], name=op.f('fk_core_eia860__scd_generators_multifuel_energy_source_code_2_core_eia__codes_energy_sources')),
sa.ForeignKeyConstraint(['operational_status_code'], ['core_eia__codes_operational_status.code'], name=op.f('fk_core_eia860__scd_generators_multifuel_operational_status_code_core_eia__codes_operational_status')),
sa.ForeignKeyConstraint(['plant_id_eia', 'generator_id', 'report_date'], ['core_eia860__scd_generators.plant_id_eia', 'core_eia860__scd_generators.generator_id', 'core_eia860__scd_generators.report_date'], name=op.f('fk_core_eia860__scd_generators_multifuel_plant_id_eia_core_eia860__scd_generators')),
sa.ForeignKeyConstraint(['prime_mover_code'], ['core_eia__codes_prime_movers.code'], name=op.f('fk_core_eia860__scd_generators_multifuel_prime_mover_code_core_eia__codes_prime_movers')),
sa.ForeignKeyConstraint(['sector_id_eia'], ['core_eia__codes_sector_consolidated.code'], name=op.f('fk_core_eia860__scd_generators_multifuel_sector_id_eia_core_eia__codes_sector_consolidated')),
sa.ForeignKeyConstraint(['utility_id_eia', 'report_date'], ['core_eia860__scd_utilities.utility_id_eia', 'core_eia860__scd_utilities.report_date'], name=op.f('fk_core_eia860__scd_generators_multifuel_utility_id_eia_core_eia860__scd_utilities')),
sa.PrimaryKeyConstraint('report_date', 'utility_id_eia', 'generator_id', 'plant_id_eia', name=op.f('pk_core_eia860__scd_generators_multifuel'))
)
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('core_eia860__scd_generators_multifuel')
# ### end Alembic commands ###
1 change: 1 addition & 0 deletions src/pudl/extract/eia860.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def get_dtypes(page, **partition):
"raw_eia860__generator_wind_existing",
"raw_eia860__generator_wind_retired",
"raw_eia860__multifuel_existing",
"raw_eia860__multifuel_proposed",
"raw_eia860__multifuel_retired",
"raw_eia860__ownership",
"raw_eia860__plant",
Expand Down
115 changes: 114 additions & 1 deletion src/pudl/metadata/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,22 @@
),
"unit": "min",
},
"can_cofire_100_oil": {
"type": "boolean",
"description": "Can the generator co-fire 100 oil?",
},
"can_cofire_oil_and_gas": {
"type": "boolean",
"description": "Can the generator co-fire oil and gas?",
},
"can_fuel_switch": {
"type": "boolean",
"description": "TK",
},
"can_switch_when_operating": {
"type": "boolean",
"description": "Indicates whether the generator switches fuel while operating.",
},
aesharpe marked this conversation as resolved.
Show resolved Hide resolved
"capacity_eoy_mw": {
"type": "number",
"description": "Total end of year installed (nameplate) capacity for a plant part, in megawatts.",
Expand Down Expand Up @@ -731,7 +747,31 @@
},
"cofire_fuels": {
"type": "boolean",
"description": "Can the generator co-fire fuels?.",
"description": "Can the generator co-fire fuels?",
},
"cofire_energy_source_1": {
"type": "string",
"description": "Type of fuel.",
},
"cofire_energy_source_2": {
"type": "string",
"description": "Type of fuel.",
},
"cofire_energy_source_3": {
"type": "string",
"description": "Type of fuel.",
},
"cofire_energy_source_4": {
"type": "string",
"description": "Type of fuel.",
},
"cofire_energy_source_5": {
"type": "string",
"description": "Type of fuel.",
},
"cofire_energy_source_6": {
"type": "string",
"description": "Type of fuel.",
aesharpe marked this conversation as resolved.
Show resolved Hide resolved
},
"coincident_peak_demand_mw": {
"type": "number",
Expand Down Expand Up @@ -1071,10 +1111,26 @@
"description": "Annual demand per km2 of a given service territory.",
"unit": "MWh/km2",
},
"has_air_permit_limits": {
"type": "boolean",
"description": "True if there are air permit limits",
},
"has_demand_side_management": {
"type": "boolean",
"description": "Whether there were strategies or measures used to control electricity demand by customers",
},
"has_factors_that_limit_switching": {
"type": "boolean",
"description": "True if there are factors that limit switching.",
},
"has_other_limits": {
"type": "boolean",
"description": "True if there are other limits on the generator.",
},
"has_storage_limits": {
"type": "boolean",
"description": "True if there are storage limits",
},
"depreciation_type": {
"type": "string",
"description": (
Expand Down Expand Up @@ -1859,6 +1915,30 @@
"type": "number",
"description": "Quanity of fuel received in tons, barrel, or Mcf.",
},
"fuel_switch_energy_source_1": {
"type": "string",
"description": "TK",
},
"fuel_switch_energy_source_2": {
"type": "string",
"description": "TK",
},
"fuel_switch_energy_source_3": {
"type": "string",
"description": "TK",
},
"fuel_switch_energy_source_4": {
"type": "string",
"description": "TK",
},
"fuel_switch_energy_source_5": {
"type": "string",
"description": "TK",
},
"fuel_switch_energy_source_6": {
"type": "string",
"description": "TK",
},
"fuel_type": {
"type": "string",
"description": "Type of fuel.",
Expand Down Expand Up @@ -2491,6 +2571,14 @@
"description": "Maximum heat content per physical unit of fuel in MMBtu.",
"unit": "MMBtu",
},
"max_oil_heat_input": {
"type": "number",
"description": "TK",
},
"max_oil_output_mw": {
"type": "number",
"description": "MW",
},
"max_steam_flow_1000_lbs_per_hour": {
"type": "number",
"unit": "1000_lbs_per_hour",
Expand Down Expand Up @@ -2816,6 +2904,26 @@
),
"unit": "MWh",
},
"net_summer_capacity_with_natural_gas_mw": {
"type": "number",
"description": "Summer capacity with natural gas.",
"unit": "MWh",
},
"net_summer_capacity_with_oil_mw": {
"type": "number",
"description": "Summer capacity with oil.",
"unit": "MWh",
},
"net_winter_capacity_with_natural_gas_mw": {
"type": "number",
"description": "Winter capacity with natural gas.",
"unit": "MWh",
},
"net_winter_capacity_with_oil_mw": {
"type": "number",
"description": "Winter capacity with oil",
"unit": "MWh",
},
"net_wheeled_power_mwh": {
"type": "number",
"description": (
Expand Down Expand Up @@ -3684,6 +3792,7 @@
"type": "string",
"description": "Human-readable name of a US Census region.",
},
"regulatory_limits": {"type": "string", "description": "TK"},
"regulation_mercury": {
"type": "string",
"description": "Most stringent type of statute or regulation code under which the boiler is operating for mercury control standards.",
Expand Down Expand Up @@ -4478,6 +4587,10 @@
"rate programs."
),
},
"time_to_switch": {
"type": "string",
"description": "Time needed to switch between fuel sources",
},
"timezone": {
"type": "string",
"description": "IANA timezone name",
Expand Down
69 changes: 69 additions & 0 deletions src/pudl/metadata/resources/eia860.py
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,75 @@
"sources": ["eia860"],
"etl_group": "eia860",
},
"core_eia860__scd_generators_multifuel": {
"description": (
"Annually reported information about energy storage from EIA-860 Schedule 3. "
"Contains data on fuel-switching and the use of multiple fuels by surveyed generators."
aesharpe marked this conversation as resolved.
Show resolved Hide resolved
),
"schema": {
"fields": [
"report_date",
"utility_id_eia",
"utility_name_eia",
"plant_id_eia",
"plant_name_eia",
"state",
"county",
"generator_id",
"operational_status_code",
"technology_description",
"prime_mover_code",
"sector_name_eia",
"sector_id_eia",
"capacity_mw",
"summer_capacity_mw",
"winter_capacity_mw",
"current_planned_generator_operating_date",
"energy_source_code_1",
"energy_source_code_2",
"multiple_fuels",
"cofire_fuels",
"cofire_energy_source_1",
"cofire_energy_source_2",
"cofire_energy_source_3",
"cofire_energy_source_4",
"cofire_energy_source_5",
"cofire_energy_source_6",
"switch_oil_gas",
"can_switch_when_operating",
"net_summer_capacity_with_natural_gas_mw",
"net_summer_capacity_with_oil_mw",
"net_winter_capacity_with_natural_gas_mw",
"net_winter_capacity_with_oil_mw",
"has_factors_that_limit_switching",
"has_storage_limits",
"has_air_permit_limits",
"has_other_limits",
"can_cofire_oil_and_gas",
"can_cofire_100_oil",
"max_oil_heat_input",
"max_oil_output_mw",
"can_fuel_switch",
"time_to_switch",
"regulatory_limits",
"fuel_switch_energy_source_1",
"fuel_switch_energy_source_2",
"fuel_switch_energy_source_3",
"fuel_switch_energy_source_4",
"fuel_switch_energy_source_5",
"fuel_switch_energy_source_6",
],
"primary_key": [
"report_date",
"utility_id_eia",
"generator_id",
"plant_id_eia",
],
},
"field_namespace": "eia",
"sources": ["eia860"],
"etl_group": "eia860",
},
}
"""EIA-860 resource attributes organized by PUDL identifier (``resource.name``).

Expand Down
Loading