Skip to content

Use Case: Adding Utility Compensation Mechanism

Kseniya Husak edited this page Aug 2, 2021 · 7 revisions

Currently all dGen restored databases reflect existing utility compensation mechanisms for excess generation. It can be useful, however, to model a scenario with a different compensation mechanism to evaluate utility policy effects. Users can do so by modifying the appropriate restored agent SQL table. This section outlines the process for such modification. We will use Wisconsin Light & Power utility to add a "net billing" compensation option. You will need to utilize PgAdmin as well as Jupyter Notebook.

A pre-populated jupyter notebook detailing these steps can be found here.

Step 1: Open a new Jupyter Notebook and Import the necessary modules/packages:


import pandas as pd 
import numpy as np 
import psycopg2 as pg 
import sqlalchemy 
from sqlalchemy import create_engine

Step 2: Check pandas’ version to ensure it is 1.1.5:


print(pd.__version__)

If you have a later version of pandas, downgrade your version by running the following command:

pip install pandas==1.1.5

Once it’s finished installed, restart your kernel.

Step 3: Launch PgAdmin and connect to your restored DB


Step 4: In your Jupyter NB connect to the docker OS DB by running the following:


engine2 = create_engine("postgresql+psycopg2://postgres:[email protected]:5432/dgen_db")

con2 = engine2.connect()

Note: If you used a port other than 5432 to restore the database or if you named your database something other than "dgen_db", you will need to update the string to reflec that.

Step 5: In PgAdmin, rename the original "nem_scenario_bau_by_utility_2019" table to "nem_scenario_bau_by_utility_2019_og":


Open the Query Tool in PgAdmin:

Then run the following command to rename the table:

ALTER TABLE diffusion_shared.nem_scenario_bau_by_utility_2019 RENAME TO nem_scenario_bau_by_utility_2019_og; 

Step 6: Create a new empty table titled "nem_scenario_bau_by_utility_2019" and add field definitions"

CREATE TABLE diffusion_shared.nem_scenario_bau_by_utility_2019
(
    utility_name text COLLATE pg_catalog."default",
    eia_id text COLLATE pg_catalog."default",
    state_abbr character varying(2) COLLATE pg_catalog."default",
    sector_abbr character varying(3) COLLATE pg_catalog."default",
    min_pv_kw_limit double precision,
    max_pv_kw_limit double precision,
    pv_pctload_limit double precision,
    rec_ownership character varying(25) COLLATE pg_catalog."default",
    compensation_style character varying(50) COLLATE pg_catalog."default",
    sell_dollar_p_kwh double precision,
    first_year integer,
    sunset_year integer
)
WITH (
    OIDS = FALSE
)
TABLESPACE pg_default;

ALTER TABLE diffusion_shared.nem_scenario_bau_by_utility_2019
    OWNER to postgres;

Step7: Grab all the data from "nem_scenario_bau_by_utility_2019_og" (the original table) as a dataframe:

sql = '''SELECT * FROM diffusion_shared.nem_scenario_bau_by_utility_2019_og''' 
nem_df = pd.read_sql(sql, con2) 

Step 8: Create a list of all variables reflecting the NEM option for each respective sector and append it to the copied dataframe. The list should consist of ordered values that will populate the following table:

For example, to add a ‘net billing’ option for Wisconsin Power & Light Co, you would do:

res = ['Wisconsin Power & Light Co','20856','WI','res', 0, 20, None, None, 'net billing', 0.04293, 0, 3000] 
com = ['Wisconsin Power & Light Co','20856','WI','com',0, 20, None, None,'net billing', 0.04293, 0, 3000] 

Note: You will need to calculate the wholesale price based on the BAs assigned to the utility.

To calculate wholesale price value:

  1. Lookup up the ReEDS BA values for your utility. You can do so by filtering respective agent file by utility eia_id. In this example we will use '20856'.
res_agents[(res_agents.county_id.isin(ids)) & (res_agents.eia_id=='20856')]['ba'].unique()

array(['p79', 'p78', 'p76', 'p75', 'p77'], dtype=object)
  1. Find wholesale prices for these BAs in the appropriate wholesale electricity prices data file for the year 2019. This will depend on which prices scenario you are running for your model. In our example we are using the following file: https://github.com/NREL/dgen/blob/master/dgen_os/input_data/wholesale_electricity_prices/ATB19_Mid_Case_wholesale.csv

Since the price difference between p75 and p76 is negligible, we will use 4 of the 5 BAs - p76 through p79.

  1. Calculate the average of wholesale prices across BAs for 2019. This is the number you will use for both res and com rows.

Append both lists to the new dataframe:

new_df.loc[new_df.index.max()+1] = res 
new_df.loc[new_df.index.max()+1] = com 

Step 9: Write the amended dataframe to the empty “nem_scenario_bau_by_utility_2019” table created in Step 6.

tbl_name = 'nem_scenario_bau_by_utility_2019' 
new_df.to_sql(tbl_name, engine2, schema='diffusion_shared', if_exists='append', index=False) 

Once you’re finished, you can run the model to reflect the update.