Skip to content
This repository was archived by the owner on Sep 27, 2023. It is now read-only.

Commit 70c4019

Browse files
committed
Add create_childs tool (#1335)
Signed-off-by: David P. Chassin <[email protected]>
1 parent 0d2a7ec commit 70c4019

File tree

3 files changed

+195
-8
lines changed

3 files changed

+195
-8
lines changed

geodata/geodata_powerline.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ def TODO(value=float('nan')):
196196
}
197197

198198
default_config = {
199-
"cabletype_file" : f"{GLD_ETC}/gridlabd/geodata_powerline_cabletypes.csv",
199+
"cabletype_file" : f"{GLD_ETC}/geodata_powerline_cabletypes.csv",
200200
}
201201

202202
OPTIONS = default_options

tools/Makefile.mk

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,29 @@
1+
dist_pkgdata_DATA += tools/create_childs.py
12
dist_pkgdata_DATA += tools/create_ductbank.py
23
dist_pkgdata_DATA += tools/create_filter.py
3-
dist_pkgdata_DATA += tools/create_player.py
44
dist_pkgdata_DATA += tools/create_meters.py
5+
dist_pkgdata_DATA += tools/create_player.py
56
dist_pkgdata_DATA += tools/create_poles.py
67
dist_pkgdata_DATA += tools/create_schedule.py
78
dist_pkgdata_DATA += tools/eia_recs.py
89
dist_pkgdata_DATA += tools/find_location.py
9-
dist_pkgdata_DATA += tools/fire_report.py
1010
dist_pkgdata_DATA += tools/fire_danger.py
11+
dist_pkgdata_DATA += tools/fire_report.py
1112
dist_pkgdata_DATA += tools/fit_filter.py
13+
dist_pkgdata_DATA += tools/gldserver.py
1214
dist_pkgdata_DATA += tools/gridlabd-editor.png
1315
dist_pkgdata_DATA += tools/gridlabd-editor.py
1416
dist_pkgdata_DATA += tools/group.py
1517
dist_pkgdata_DATA += tools/insights.py
1618
dist_pkgdata_DATA += tools/install.py
1719
dist_pkgdata_DATA += tools/isone.py
1820
dist_pkgdata_DATA += tools/market_data.py
19-
dist_pkgdata_DATA += tools/mdb_info.py
2021
dist_pkgdata_DATA += tools/market_model.py
21-
dist_pkgdata_DATA += tools/meteostat_weather.py
22+
dist_pkgdata_DATA += tools/mdb_info.py
2223
dist_pkgdata_DATA += tools/metar2glm.py
23-
dist_pkgdata_DATA += tools/read_dlp.py
24-
dist_pkgdata_DATA += tools/gldserver.py
24+
dist_pkgdata_DATA += tools/meteostat_weather.py
2525
dist_pkgdata_DATA += tools/noaa_forecast.py
2626
dist_pkgdata_DATA += tools/nsrdb_weather.py
27-
dist_pkgdata_DATA += tools/ucar_weather.py
2827
dist_pkgdata_DATA += tools/pole_analysis.py
28+
dist_pkgdata_DATA += tools/read_dlp.py
29+
dist_pkgdata_DATA += tools/ucar_weather.py

tools/create_childs.py

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
# Syntax: create_childs [-i|--input=INPUTFILE] [-o|--output=GLMFILE] [OPTIONS ...]
2+
"""Syntax: create_childs [-i|--input=INPUTFILE] [-o|--output=GLMFILE] [OPTIONS ...]
3+
4+
Options
5+
-------
6+
-P|--parents=NAME:VALUE,... specify parent property pattern to match (required)
7+
-C|--childs=NAME:VALUE,... specify child property list to assign (required)
8+
-N|--names=STRING specify object naming convention (default is '{class}_{name}')
9+
-M|--modules=NAME,... specify module names to use (defaults to those found)
10+
11+
Description
12+
-----------
13+
14+
The `create_childs` tool adds child objects to all objects that match the
15+
parent object pattern specified.
16+
17+
Parent patterns and child properties as specified as a comma-separate list of
18+
`NAME:VALUE` strings, e.g., `class:node` or `nominal_voltage:2.4kV`. Parent
19+
patterns use `regex` pattern matching. Child properties may include `{NAME}`
20+
format strings where `NAME` is a property of the parent object. This
21+
allows copying of values from the parent object. This formatting also can be
22+
applied to the naming string, e.g., `-N='{name}_L' to append '_L' to the
23+
parent object name.
24+
25+
Example
26+
-------
27+
28+
The following creates a GLM file containing a `triplex_load` objects attached
29+
to `triplex_node` objects with names starting as `N_` in the file `my-network.json`:
30+
31+
~~~
32+
$ gridlabd create_childs -i=my-network.json -o=loads.glm -P='class:triplex_node,name:^N_' -C='class:triplex_load,nominal_voltage:{nominal_voltage},phases:{phases},constant_power_B:1.2+0.1jkVA'
33+
~~~
34+
"""
35+
36+
import sys, os
37+
import json
38+
import re
39+
import datetime
40+
import subprocess
41+
import random
42+
43+
EXENAME = os.path.splitext(os.path.basename(sys.argv[0]))[0]
44+
45+
DEBUG = False
46+
WARNING = True
47+
QUIET = False
48+
VERBOSE = False
49+
50+
E_OK = 0
51+
E_INVALID = 1
52+
E_FAILED = 2
53+
E_SYNTAX = 8
54+
E_EXCEPTION = 9
55+
EXITCODE = E_OK
56+
57+
class GldException(Exception):
58+
pass
59+
60+
def error(msg,code=None):
61+
if type(code) is int:
62+
global EXITCODE
63+
EXITCODE = code
64+
if DEBUG:
65+
raise GldException(msg)
66+
print("ERROR [create_childs]:",msg,file=sys.stderr)
67+
exit(code)
68+
69+
70+
def load():
71+
72+
if not INPUTFILE.endswith(".json"):
73+
tmpfile = "."
74+
while os.path.exists(tmpfile):
75+
tmpfile = f"tmp{hex(random.randint(1e30,1e31))[2:]}.json"
76+
try:
77+
result = subprocess.run(["gridlabd","-C",INPUTFILE,"-o",tmpfile])
78+
assert(result.returncode==0)
79+
with open(tmpfile,"r") as fh:
80+
model = json.load(fh)
81+
except:
82+
raise
83+
finally:
84+
os.remove(tmpfile)
85+
pass
86+
else:
87+
with open(INPUTFILE,"r") as fh:
88+
model = json.load(fh)
89+
return model
90+
91+
def save(fh):
92+
print(f"// generated by '{' '.join(sys.argv)}' at {datetime.datetime.now()}",file=fh)
93+
for name in MODULES:
94+
print(f"module {name};",file=fh)
95+
classname = CHILDS["class"]
96+
for obj,data in OBJECTS.items():
97+
print(f"object {classname} {{",file=fh)
98+
for prop,value in data.items():
99+
print(f" {prop} \"{value}\";",file=fh)
100+
print("}",file=fh)
101+
102+
def main():
103+
104+
PATTERN = {}
105+
for name,pattern in PARENTS.items():
106+
PATTERN[name] = re.compile(pattern)
107+
108+
if "class" not in CHILDS:
109+
error("you must include a class name in the child properties",E_INVALID)
110+
classname = CHILDS["class"]
111+
model = load()
112+
assert(model['application']=='gridlabd')
113+
global MODULES
114+
if not MODULES:
115+
MODULES = list(model['modules'])
116+
117+
for obj,data in model['objects'].items():
118+
data['name'] = obj
119+
ok = True
120+
for name,pattern in PATTERN.items():
121+
if not pattern.match(data[name]):
122+
ok = False
123+
break
124+
if ok:
125+
name = f"{classname}_{obj}" if NAMING is None else NAMING.format(**data)
126+
OBJECTS[name] = dict(parent=obj,name=name)
127+
for prop,value in CHILDS.items():
128+
if not prop in ["class"]:
129+
OBJECTS[name][prop] = value.format(**data)
130+
131+
if OUTPUTFILE.endswith(".glm"):
132+
with open(OUTPUTFILE,"w") as fh:
133+
save(fh)
134+
else:
135+
error("invalid output file format")
136+
137+
return E_OK
138+
139+
INPUTFILE = "/dev/stdin"
140+
OUTPUTFILE = "/dev/stdout"
141+
PARENTS = None
142+
CHILDS = None
143+
NAMING = None
144+
OBJECTS = {}
145+
MODULES = []
146+
147+
if __name__ == "__main__":
148+
149+
if len(sys.argv) == 1:
150+
print(__doc__.split('\n')[0],file=sys.stderr)
151+
exit(E_SYNTAX)
152+
153+
for arg in sys.argv[1:]:
154+
spec = arg.split("=")
155+
if len(spec) == 1:
156+
tag = arg
157+
value = None
158+
else:
159+
tag = spec[0]
160+
value = '='.join(spec[1:])
161+
162+
if tag in ["-h","--help","help"]:
163+
print(__doc__)
164+
exit(E_OK)
165+
if tag in ["-i","--input"]:
166+
INPUTFILE = value if value else "/dev/stdin"
167+
elif tag in ["-o","--output"]:
168+
OUTPUTFILE = value if value else "/dev/stdout"
169+
elif tag in ["-P","--parent"]:
170+
PARENTS = dict([x.split(":") for x in value.split(",")])
171+
elif tag in ["-C","--childs"]:
172+
CHILDS = dict([x.split(":") for x in value.split(",")])
173+
elif tag in ["-N","--names"]:
174+
NAMING = value
175+
elif tag in ["-M","--modules"]:
176+
MODULES = value.split(",")
177+
else:
178+
error(f"option '{arg}' is invalid",E_INVALID)
179+
180+
if PARENTS is None:
181+
error("you must specify the parent patterns to match")
182+
if CHILDS is None:
183+
error("you must specify the child properties to define")
184+
185+
EXITCODE = main()
186+
exit(EXITCODE)

0 commit comments

Comments
 (0)