-
Notifications
You must be signed in to change notification settings - Fork 4
/
CAISO_LMP.py
115 lines (105 loc) · 5 KB
/
CAISO_LMP.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# Developed by Greg Miller, grmiller@ucdavis.edu
# Version 1
# Last Updated January 16, 2019
# Purpose: To create a shapefile and csv file of Locational Marginal Pricing Nodes in CAISO and most of WECC http://wwwmobile.caiso.com/Web.Service.Chart/pricecontourmap.html
import csv
import json
import pandas as pd
from pathlib import Path
import requests
import shapefile
#global constants
price_map_url = "http://wwwmobile.caiso.com/Web.Service.Chart/api/v3/ChartService/PriceContourMap1"
"""
json document tree
<PriceContourMapDto>
<l>
<PriceContourLayer> <l>3</l>
<m>
<PriceCountourMarker> #each LMP node
<c xmlns:d6p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d6p1:decimal>40.53944</d6p1:decimal> #latitude
<d6p1:decimal>-111.89667</d6p1:decimal> #longitude
</c>
<dc>52.81386</dc> #Day-ahead energy $
<dg>-3.52064</dg> #Day-ahead congestion $
<dk>0</dk> #price color code
<dl>-2.26571</dl> #Day-ahead losses $
<do>1</do> #unique ordering key for each node
<dp>47.02751</dp> #Day-ahead price $
<fc>56.60284</fc> #Fifteen Minute Market energy $
<fg>0</fg> #FMM congestion $
<fk>1</fk>
<fl>-3.01127</fl> #FMM losses $
<fo>1</fo>
<fp>53.59157</fp> #FMM price $
<n>118THSO_LNODER1</n> #Node Name
<p>LOAD</p> #Load Type
<qc>73.41486</qc> #Real-Time Dispatch energy $
<qg>-0.0024</qg> #RTD congestion $
<qk>4</qk>
<ql>-3.94959</ql> #RTD losses $
<qo>1</qo>
<qp>69.46287</qp> #RTD price $
<t>Node</t>
</PriceContourMarker>
"""
lmp_csv = Path.cwd() / "LMP_coordinates.csv"
def get_lmp_loc(): # This function has been adapted from WattTime/pyiso/caiso.py commit c99beaf44436753d30e48cc7f8f692d3a524d2c5 r24mille committed on Dec 14, 2017
"""
CURRENTLY INCONSISTENTLY FAILING
status 401, response content "Access is restricted to authorized clients."
FORMERLY CONSISTENT BEHAVIOR:
Returns a list of dictionaries containing node atlas data. Each
dictionary will contain
{'node_id': <name of the node>
'latitide': <latitude of the node>,
'longitude': <longitude of the node>,
'area': <control area the node belongs to>}
This list is generated by parsing the JSON returned from the CAISO
price map URL:
http://wwwmobile.caiso.com/Web.Service.Chart/api/v3/ChartService/PriceContourMap1
This json is what is used in the interactive CAISO price
contour map found at:
http://wwwmobile.caiso.com/Web.Service.Chart/pricecontourmap.html
This retuned JSON does not contain geographic data for all CAISO
pricing nodes
"""
# get json from the price map url used in the CAISO interactive price
# map http://wwwmobile.caiso.com/Web.Service.Chart/pricecontourmap.html
r = requests.get(price_map_url)
json_obj = r.json()
# parse the json to create the node location dictionary
node_entries = json_obj['l'][2]['m']
return_dict = [{'node_id': str(entry['n']),
'latitude': entry['c'][0],
'longitude': entry['c'][1],
'area': str(entry['a']),
'node_type': str(entry['p'])} for entry in node_entries]
return return_dict
def main():
lmp_dict = get_lmp_loc()
df_lmp = pd.DataFrame.from_dict(lmp_dict)
with open(lmp_csv,'w+') as f:
df_lmp.to_csv(f, header=True, index=False, lineterminator='\n')
csv_to_shp()
print("Shapefile created")
def csv_to_shp(): #adapted from https://glenbambrick.com/2016/01/09/csv-to-shapefile-with-pyshp/
lmp_shp = shapefile.Writer(Path.cwd() / "LMP/caiso_lmp", shapeType=shapefile.POINT)
lmp_shp.autoBalance = 1 #This enforces that for every record there must be a corresponding geometry.
lmp_shp.field("AREA","C") #create field names and data types
lmp_shp.field("NODE_ID","C")
lmp_shp.field("TYPE","C")
with open(lmp_csv) as csvfile:
reader = csv.reader(csvfile,delimiter=',')
next(reader,None)
for row in reader:
area = row[0]
latitude = row[1]
longitude = row[2]
node_id = row[3]
node_type = row[4]
lmp_shp.point(float(longitude),float(latitude)) #set geometry for each record
lmp_shp.record(area, node_id, node_type) #create matching record for the geometry using the attributes
if __name__== "__main__":
main()