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

Release 4.3.7 #171

Merged
merged 11 commits into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cloud/servers/version.gridlabd.us/aws_requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pandas>=1.3.5
numpy>=1.22.2 # not directly required, pinned by Snyk to avoid a vulnerability
3 changes: 3 additions & 0 deletions converters/Makefile.mk
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ dist_pkgdata_DATA += converters/mdb-table2glm-player.py
# omd -> glm
dist_pkgdata_DATA += converters/omd2glm.py

# py->glm
dist_pkgdata_DATA += converters/py2glm.py

# tmy3 -> glm
dist_pkgdata_DATA += converters/tmy32glm.py

Expand Down
2 changes: 2 additions & 0 deletions converters/autotest/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ solver_nr_profile.csv
table2glm_input_noclass.glm
table2glm_input_noname.glm
table2glm_input.glm
pypower_casedata.py
pypower_results.py
38 changes: 33 additions & 5 deletions converters/csv-ami2glm-player.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,19 @@ def write_player(file, obj, node_ID, phase) :
file.write('object player {\n')
file.write('\tparent "' + obj + '";\n')
file.write('\tfile "' + os.path.join(folder_name,str(node_ID)) + '.csv";\n')
file.write(f'\tproperty constant_power_{phase};\n')
for p in phase :
file.write(f'\tproperty constant_power_{p};\n')
file.write('}\n')

def filter_dict_by_min_value(input_dict, patterns):
result_dict = {}
for pattern in patterns:
pattern_dictionary = {key: value for key, value in input_dict.items() if pattern in key}
min_value = min(pattern_dictionary.values())
min_dict = {key: value for key, value in pattern_dictionary.items() if value == min_value}
result_dict.update(min_dict)
return list(result_dict.keys())

def convert(input_files, output_file, options={}):

if type(input_files) is dict:
Expand Down Expand Up @@ -106,6 +116,8 @@ def convert(input_files, output_file, options={}):
df.to_csv(os.path.join(folder_name,os.path.basename(output_file)), index=False)
elif os.path.splitext(output_file)[1]=='.glm' :
phase_dict = {}
load_list = {}
load_list_filtered = {}
with open(output_file, mode='w') as file :
file.write('module tape;\n')

Expand All @@ -114,11 +126,27 @@ def convert(input_files, output_file, options={}):
continue
for obj,val in network["objects"].items() :
if "load" in val["class"] and node_ID in obj:
node_phase = ''.join([x for x in 'ABC' if x in val['phases']])
volts = float(val['nominal_voltage'].split(' ')[0])
if 'k' in val['nominal_voltage'].split(' ')[1] :
load_list[obj] = volts*1000
elif 'M' in val['nominal_voltage'].split(' ')[1] :
load_list[obj] = volts*1000000
else :
load_list[obj] = volts
load_phase = ''.join([x for x in 'ABC' if x in val['phases']])
phase_dict[node_ID]=load_phase


# Grabbing only loads on the low side of the Transformer
load_list_filtered = filter_dict_by_min_value(load_list,node_ID_set)
for load_ID in load_list_filtered :
for obj, val in network["objects"].items() :
if load_ID==obj :
load_phase = ''.join([x for x in 'ABC' if x in val['phases']])
parent = val["parent"]
phase_dict[node_ID]=node_phase
for p in node_phase :
write_player(file, obj, node_ID, p)
for node_ID in node_ID_set :
if node_ID in load_ID :
write_player(file, obj, node_ID, load_phase)

new_column_names = {
'reading_dttm': 'timestamp',
Expand Down
133 changes: 133 additions & 0 deletions converters/py2glm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import json
import os
import sys, getopt
import datetime
import importlib, copy
from importlib import util


config = {"input":"py","output":"glm","type":["pypower"]}

def help():
return """py2glm.py -i <inputfile> -o <outputfile> [options...]
-c|--config output converter configuration data
-h|--help output this help
-i|--ifile <filename> [REQUIRED] PY input file
-o|--ofile <filename> [OPTIONAL] GLM output file name
-t|--type type of input file
-N|--name do not autoname objects
"""

def main():
filename_py = None
filename_glm = None
py_type = 'pypower'
autoname = True
try :
opts, args = getopt.getopt(sys.argv[1:],
"chi:o:t:N",
["config","help","ifile=","ofile=","type=","name"],
)
except getopt.GetoptError:
sys.exit(2)
if not opts :
print('ERROR [py2glm.py]: missing command arguments')
sys.exit(2)
for opt, arg in opts:
if opt in ("-c","--config"):
print(config)
sys.exit()
elif opt in ("-h","--help"):
print(help())
sys.exit()
elif opt in ("-i", "--ifile"):
filename_py = arg
elif opt in ("-o", "--ofile"):
filename_glm = arg
elif opt in ("-t", "--type"):
py_type = arg
elif opt in ("-N","--name"):
autoname = False
else :
print(f"ERROR [py2glm.py]: {opt}={arg} is not a valid option")
sys.exit(1)

if not filename_py:
print(f"ERROR [py2glm.py]: input filename not specified")
sys.exit(1)

try:
convert(
ifile = filename_py,
ofile = filename_glm,
options = dict(
py_type = py_type,
autoname = autoname),
)
except Exception as err:
print(f"ERROR [py2glm.py]: {err}")
import traceback
traceback.print_exception(err,file=sys.stderr)
sys.exit(9)

def convert(ifile,ofile,options={}):
"""Default converter is pypower case"""

py_type = options['py_type'] if 'py_type' in options else "pypower"
autoname = options['autoname'] if 'autoname' in options else True

assert(py_type in ['pypower'])

modspec = util.spec_from_file_location("glm",ifile)
modname = os.path.splitext(ifile)[0]
mod = importlib.import_module(os.path.basename(modname))
casedef = getattr(mod,os.path.basename(modname))
data = casedef()

NL='\n'
with open(ofile,"w") as glm:
glm.write(f"""// generated by {' '.join(sys.argv)}
module pypower
{{
version {data['version']};
baseMVA {data['baseMVA']};
}}
""")

for name,spec in dict(
# pypower properties must be in the save order as the case array columns
bus = "bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin",
gen = "bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin Pc1 Pc2 Qc1min"\
+ " Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf",
branch = "fbus tbus r x b rateA rateB rateC ratio angle status angmin angmax",
).items():
glm.write(f"{NL}//{NL}// {name}{NL}//{NL}")
for n,line in enumerate(data[name]):
oname = f"{NL} name pp_{name}_{n+1};" if autoname else ""
glm.write(f"""object pypower.{name}
{{{oname}
{NL.join([f" {x} {line[n]};" for n,x in enumerate(spec.split())])}
}}
""")
if 'gencost' in data:
glm.write("\n//\n// gencost\n//\n")
for n,line in enumerate(data['gencost']):
model = line[0]
startup = line[1]
shutdown = line[2]
count = line[3]
costs = line[4:]
assert(len(costs)==count)
oname = f"{NL} name pp_gencost_{n};" if autoname else ""
glm.write(f"""object pypower.gencost
{{{oname}
model {int(model)};
startup {startup};
shutdown {shutdown};
costs "{','.join([str(x) for x in costs])}";
}}
""")

if __name__ == '__main__':
main()

24 changes: 24 additions & 0 deletions docs/Converters/Import/PyPower_cases.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[[/Converters/Import/Ami_data]] -- AMI data import

# Synopsis

GLM:

~~~
#input "casefile.py" -t pypower [-N|--name]
~~~

Shell:

~~~
$ gridlabd convert -i inputfile.py -o outputfile.glm -t pypower [-N|--name]
~~~

# Description

The `py2glm.py` converter support conversion of PyPower case files to GLM
models. The `-N|--name` option suppresses autonaming of PyPower objects.

# See also

* [[/Module/Pypower]]
Loading
Loading