topologicpy 0.4.8__py3-none-any.whl → 0.4.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- topologicpy/Aperture.py +46 -0
- topologicpy/Cell.py +1780 -0
- topologicpy/CellComplex.py +791 -0
- topologicpy/Cluster.py +591 -0
- topologicpy/Color.py +157 -0
- topologicpy/Context.py +56 -0
- topologicpy/DGL.py +2661 -0
- topologicpy/Dictionary.py +470 -0
- topologicpy/Edge.py +855 -0
- topologicpy/EnergyModel.py +1052 -0
- topologicpy/Face.py +1810 -0
- topologicpy/Graph.py +3526 -0
- topologicpy/Graph_Export.py +858 -0
- topologicpy/Grid.py +338 -0
- topologicpy/Helper.py +182 -0
- topologicpy/Honeybee.py +424 -0
- topologicpy/Matrix.py +255 -0
- topologicpy/Neo4jGraph.py +311 -0
- topologicpy/Plotly.py +1396 -0
- topologicpy/Polyskel.py +524 -0
- topologicpy/Process.py +1368 -0
- topologicpy/SQL.py +48 -0
- topologicpy/Shell.py +1418 -0
- topologicpy/Speckle.py +433 -0
- topologicpy/Topology.py +5854 -0
- topologicpy/UnitTest.py +29 -0
- topologicpy/Vector.py +555 -0
- topologicpy/Vertex.py +714 -0
- topologicpy/Wire.py +2346 -0
- topologicpy/__init__.py +20 -0
- topologicpy/bin/linux/topologic/__init__.py +2 -0
- topologicpy/bin/linux/topologic/topologic.cpython-310-x86_64-linux-gnu.so +0 -0
- topologicpy/bin/linux/topologic/topologic.cpython-311-x86_64-linux-gnu.so +0 -0
- topologicpy/bin/linux/topologic/topologic.cpython-38-x86_64-linux-gnu.so +0 -0
- topologicpy/bin/linux/topologic/topologic.cpython-39-x86_64-linux-gnu.so +0 -0
- topologicpy/bin/linux/topologic.libs/libTKBO-6bdf205d.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKBRep-2960a069.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKBool-c44b74bd.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKFillet-9a670ba0.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKG2d-8f31849e.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKG3d-4c6bce57.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKGeomAlgo-26066fd9.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKGeomBase-2116cabe.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKMath-72572fa8.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKMesh-2a060427.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKOffset-6cab68ff.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKPrim-eb1262b3.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKShHealing-e67e5cc7.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKTopAlgo-e4c96c33.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKernel-fb7fe3b7.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libgcc_s-32c1665e.so.1 +0 -0
- topologicpy/bin/linux/topologic.libs/libstdc++-672d7b41.so.6.0.30 +0 -0
- topologicpy/bin/windows/topologic/TKBO-f6b191de.dll +0 -0
- topologicpy/bin/windows/topologic/TKBRep-e56a600e.dll +0 -0
- topologicpy/bin/windows/topologic/TKBool-7b8d47ae.dll +0 -0
- topologicpy/bin/windows/topologic/TKFillet-0ddbf0a8.dll +0 -0
- topologicpy/bin/windows/topologic/TKG2d-2e2dee3d.dll +0 -0
- topologicpy/bin/windows/topologic/TKG3d-6674513d.dll +0 -0
- topologicpy/bin/windows/topologic/TKGeomAlgo-d240e370.dll +0 -0
- topologicpy/bin/windows/topologic/TKGeomBase-df87aba5.dll +0 -0
- topologicpy/bin/windows/topologic/TKMath-45bd625a.dll +0 -0
- topologicpy/bin/windows/topologic/TKMesh-d6e826b1.dll +0 -0
- topologicpy/bin/windows/topologic/TKOffset-79b9cc94.dll +0 -0
- topologicpy/bin/windows/topologic/TKPrim-aa430a86.dll +0 -0
- topologicpy/bin/windows/topologic/TKShHealing-bb48be89.dll +0 -0
- topologicpy/bin/windows/topologic/TKTopAlgo-7d0d1e22.dll +0 -0
- topologicpy/bin/windows/topologic/TKernel-08c8cfbb.dll +0 -0
- topologicpy/bin/windows/topologic/__init__.py +2 -0
- topologicpy/bin/windows/topologic/topologic.cp310-win_amd64.pyd +0 -0
- topologicpy/bin/windows/topologic/topologic.cp311-win_amd64.pyd +0 -0
- topologicpy/bin/windows/topologic/topologic.cp38-win_amd64.pyd +0 -0
- topologicpy/bin/windows/topologic/topologic.cp39-win_amd64.pyd +0 -0
- {topologicpy-0.4.8.dist-info → topologicpy-0.4.9.dist-info}/METADATA +1 -1
- topologicpy-0.4.9.dist-info/RECORD +77 -0
- topologicpy-0.4.9.dist-info/top_level.txt +1 -0
- topologicpy-0.4.8.dist-info/RECORD +0 -5
- topologicpy-0.4.8.dist-info/top_level.txt +0 -1
- {topologicpy-0.4.8.dist-info → topologicpy-0.4.9.dist-info}/LICENSE +0 -0
- {topologicpy-0.4.8.dist-info → topologicpy-0.4.9.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,1052 @@
|
|
|
1
|
+
import topologicpy
|
|
2
|
+
import topologic
|
|
3
|
+
from topologicpy.Topology import Topology
|
|
4
|
+
from topologicpy.Dictionary import Dictionary
|
|
5
|
+
|
|
6
|
+
import math
|
|
7
|
+
from collections import OrderedDict
|
|
8
|
+
import os
|
|
9
|
+
from os.path import exists
|
|
10
|
+
import json
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
import sys
|
|
13
|
+
import subprocess
|
|
14
|
+
try:
|
|
15
|
+
from tqdm.auto import tqdm
|
|
16
|
+
except:
|
|
17
|
+
import sys, subprocess
|
|
18
|
+
call = [sys.executable, '-m', 'pip', 'install', 'tqdm', '-t', sys.path[0]]
|
|
19
|
+
subprocess.run(call)
|
|
20
|
+
try:
|
|
21
|
+
from tqdm.auto import tqdm
|
|
22
|
+
except:
|
|
23
|
+
print("EnergyModel - ERROR: Could not import tqdm")
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
import openstudio
|
|
27
|
+
openstudio.Logger.instance().standardOutLogger().setLogLevel(openstudio.Fatal)
|
|
28
|
+
except:
|
|
29
|
+
call = [sys.executable, '-m', 'pip', 'install', 'openstudio', '-t', sys.path[0]]
|
|
30
|
+
subprocess.run(call)
|
|
31
|
+
try:
|
|
32
|
+
import openstudio
|
|
33
|
+
openstudio.Logger.instance().standardOutLogger().setLogLevel(openstudio.Fatal)
|
|
34
|
+
except:
|
|
35
|
+
print("EnergyModel - ERROR: Could not import openstudio")
|
|
36
|
+
|
|
37
|
+
class EnergyModel:
|
|
38
|
+
'''
|
|
39
|
+
@staticmethod
|
|
40
|
+
def ByOSMFile(file):
|
|
41
|
+
"""
|
|
42
|
+
Creates an EnergyModel from the input OSM file path.
|
|
43
|
+
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
path : string
|
|
47
|
+
The path to the input .OSM file.
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
openstudio.openstudiomodelcore.Model
|
|
52
|
+
The OSM model.
|
|
53
|
+
|
|
54
|
+
"""
|
|
55
|
+
if not file:
|
|
56
|
+
print("EnergyModel.ByOSMFile - Error: The input path is not valid. Returning None.")
|
|
57
|
+
return None
|
|
58
|
+
osModel = file.read()
|
|
59
|
+
if osModel.isNull():
|
|
60
|
+
print("EnergyModel.ByOSMFile - Error: The openstudio model is null. Returning None.")
|
|
61
|
+
return None
|
|
62
|
+
else:
|
|
63
|
+
osModel = osModel.get()
|
|
64
|
+
return osModel
|
|
65
|
+
'''
|
|
66
|
+
|
|
67
|
+
@staticmethod
|
|
68
|
+
def ByOSMPath(path: str):
|
|
69
|
+
"""
|
|
70
|
+
Creates an EnergyModel from the input OSM file path.
|
|
71
|
+
|
|
72
|
+
Parameters
|
|
73
|
+
----------
|
|
74
|
+
path : string
|
|
75
|
+
The path to the input .OSM file.
|
|
76
|
+
|
|
77
|
+
Returns
|
|
78
|
+
-------
|
|
79
|
+
openstudio.openstudiomodelcore.Model
|
|
80
|
+
The OSM model.
|
|
81
|
+
|
|
82
|
+
"""
|
|
83
|
+
if not path:
|
|
84
|
+
print("EnergyModel.ByImportedOSM - Error: The input path is not valid. Returning None.")
|
|
85
|
+
return None
|
|
86
|
+
translator = openstudio.osversion.VersionTranslator()
|
|
87
|
+
osmPath = openstudio.openstudioutilitiescore.toPath(path)
|
|
88
|
+
osModel = translator.loadModel(osmPath)
|
|
89
|
+
if osModel.isNull():
|
|
90
|
+
print("EnergyModel.ByImportedOSM - Error: The openstudio model is null. Returning None.")
|
|
91
|
+
return None
|
|
92
|
+
else:
|
|
93
|
+
osModel = osModel.get()
|
|
94
|
+
return osModel
|
|
95
|
+
|
|
96
|
+
@staticmethod
|
|
97
|
+
def ByImportedOSM(path: str):
|
|
98
|
+
"""
|
|
99
|
+
DEPRECATED. DO NOT USE. Instead use Topology.ByOSMPath or Topology.ByOSMFile
|
|
100
|
+
Creates an EnergyModel from the input OSM file path.
|
|
101
|
+
|
|
102
|
+
Parameters
|
|
103
|
+
----------
|
|
104
|
+
path : string
|
|
105
|
+
The path to the input .OSM file.
|
|
106
|
+
|
|
107
|
+
Returns
|
|
108
|
+
-------
|
|
109
|
+
openstudio.openstudiomodelcore.Model
|
|
110
|
+
The OSM model.
|
|
111
|
+
|
|
112
|
+
"""
|
|
113
|
+
print("Topology.ByImportedOSM - WARNING: This method is DEPRECATED. DO NOT USE. Instead use Topology.ByOSMPath")
|
|
114
|
+
return EnergyModel.ByOSMPath(path=path)
|
|
115
|
+
|
|
116
|
+
@staticmethod
|
|
117
|
+
def ByTopology(building : topologic.CellComplex,
|
|
118
|
+
shadingSurfaces : topologic.Topology = None,
|
|
119
|
+
osModelPath : str = None,
|
|
120
|
+
weatherFilePath : str = None,
|
|
121
|
+
designDayFilePath : str = None,
|
|
122
|
+
floorLevels : list = None,
|
|
123
|
+
buildingName : str = "TopologicBuilding",
|
|
124
|
+
buildingType : str = "Commercial",
|
|
125
|
+
northAxis : float = 0.0,
|
|
126
|
+
glazingRatio : float = 0.0,
|
|
127
|
+
coolingTemp : float = 25.0,
|
|
128
|
+
heatingTemp : float = 20.0,
|
|
129
|
+
defaultSpaceType : str = "189.1-2009 - Office - WholeBuilding - Lg Office - CZ4-8",
|
|
130
|
+
spaceNameKey : str = "TOPOLOGIC_name",
|
|
131
|
+
spaceTypeKey : str = "TOPOLOGIC_type"):
|
|
132
|
+
"""
|
|
133
|
+
Creates an EnergyModel from the input topology and parameters.
|
|
134
|
+
|
|
135
|
+
Parameters
|
|
136
|
+
----------
|
|
137
|
+
building : topologic.CellComplex
|
|
138
|
+
The input building topology.
|
|
139
|
+
shadingSurfaces : topologic.Topology , optional
|
|
140
|
+
The input topology for shading surfaces. The default is None.
|
|
141
|
+
osModelPath : str , optional
|
|
142
|
+
The path to the template OSM file. The default is "./assets/EnergyModel/OSMTemplate-OfficeBuilding-3.5.0.osm".
|
|
143
|
+
weatherFilePath : str , optional
|
|
144
|
+
The input energy plus weather (epw) file. The default is "./assets/EnergyModel/GBR_London.Gatwick.037760_IWEC.epw".
|
|
145
|
+
designDayFilePath : str , optional
|
|
146
|
+
The input design day (ddy) file path. The default is "./assets/EnergyModel/GBR_London.Gatwick.037760_IWEC.ddy",
|
|
147
|
+
floorLevels : list , optional
|
|
148
|
+
The list of floor level Z heights including the lowest most and the highest most levels. If set to None, this method will attempt to
|
|
149
|
+
find the floor levels from the horizontal faces of the input topology
|
|
150
|
+
buildingName : str , optional
|
|
151
|
+
The desired name of the building. The default is "TopologicBuilding".
|
|
152
|
+
buildingType : str , optional
|
|
153
|
+
The building type. The default is "Commercial".
|
|
154
|
+
defaultSpaceType : str , optional
|
|
155
|
+
The default space type to apply to spaces that do not have a type assigned in their dictionary. The default is "189.1-2009 - Office - WholeBuilding - Lg Office - CZ4-8".
|
|
156
|
+
northAxis : float , optional
|
|
157
|
+
The counter-clockwise angle in degrees from the positive Y-axis representing the direction of the north axis. The default is 0.0.
|
|
158
|
+
glazingRatio : float , optional
|
|
159
|
+
The glazing ratio (ratio of windows to wall) to use for exterior vertical walls that do not have apertures. If you do not wish to use a glazing ratio, set it to 0. The default is 0.
|
|
160
|
+
coolingTemp : float , optional
|
|
161
|
+
The desired temperature in degrees at which the cooling system should activate. The default is 25.0.
|
|
162
|
+
heatingTemp : float , optional
|
|
163
|
+
The desired temperature in degrees at which the heating system should activate. The default is 25.0..
|
|
164
|
+
spaceNameKey : str , optional
|
|
165
|
+
The dictionary key to use to find the space name value. The default is "Name".
|
|
166
|
+
spaceTypeKey : str , optional
|
|
167
|
+
The dictionary key to use to find the space type value. The default is "Type".
|
|
168
|
+
|
|
169
|
+
Returns
|
|
170
|
+
-------
|
|
171
|
+
openstudio.openstudiomodelcore.Model
|
|
172
|
+
The created OSM model.
|
|
173
|
+
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
def getKeyName(d, keyName):
|
|
177
|
+
keys = d.Keys()
|
|
178
|
+
for key in keys:
|
|
179
|
+
if key.lower() == keyName.lower():
|
|
180
|
+
return key
|
|
181
|
+
return None
|
|
182
|
+
|
|
183
|
+
def createUniqueName(name, nameList, number):
|
|
184
|
+
if not (name in nameList):
|
|
185
|
+
return name
|
|
186
|
+
elif not ((name+"_"+str(number)) in nameList):
|
|
187
|
+
return name+"_"+str(number)
|
|
188
|
+
else:
|
|
189
|
+
return createUniqueName(name,nameList, number+1)
|
|
190
|
+
|
|
191
|
+
def getFloorLevels(building):
|
|
192
|
+
from topologicpy.Vertex import Vertex
|
|
193
|
+
from topologicpy.CellComplex import CellComplex
|
|
194
|
+
from topologicpy.Dictionary import Dictionary
|
|
195
|
+
|
|
196
|
+
d = CellComplex.Decompose(building)
|
|
197
|
+
bhf = d['bottomHorizontalFaces']
|
|
198
|
+
ihf = d['internalHorizontalFaces']
|
|
199
|
+
thf = d ['topHorizontalFaces']
|
|
200
|
+
hf = bhf+ihf+thf
|
|
201
|
+
floorLevels = [Vertex.Z(Topology.Centroid(f)) for f in hf]
|
|
202
|
+
floorLevels = list(set(floorLevels))
|
|
203
|
+
floorLevels.sort()
|
|
204
|
+
return floorLevels
|
|
205
|
+
|
|
206
|
+
if not osModelPath:
|
|
207
|
+
import os
|
|
208
|
+
osModelPath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "assets", "EnergyModel", "OSMTemplate-OfficeBuilding-3.5.0.osm")
|
|
209
|
+
if not weatherFilePath or not designDayFilePath:
|
|
210
|
+
import os
|
|
211
|
+
weatherFilePath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "assets", "EnergyModel", "GBR_London.Gatwick.037760_IWEC.epw")
|
|
212
|
+
designDayFilePath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "assets", "EnergyModel", "GBR_London.Gatwick.037760_IWEC.ddy")
|
|
213
|
+
translator = openstudio.osversion.VersionTranslator()
|
|
214
|
+
osmFile = openstudio.openstudioutilitiescore.toPath(osModelPath)
|
|
215
|
+
osModel = translator.loadModel(osmFile)
|
|
216
|
+
if osModel.isNull():
|
|
217
|
+
print("EnergyModel.ByTopology - Error: The openstudio model is null. Returning None.")
|
|
218
|
+
return None
|
|
219
|
+
else:
|
|
220
|
+
osModel = osModel.get()
|
|
221
|
+
osEPWFile = openstudio.openstudioutilitiesfiletypes.EpwFile.load(openstudio.toPath(weatherFilePath))
|
|
222
|
+
if osEPWFile.is_initialized():
|
|
223
|
+
osEPWFile = osEPWFile.get()
|
|
224
|
+
openstudio.model.WeatherFile.setWeatherFile(osModel, osEPWFile)
|
|
225
|
+
ddyModel = openstudio.openstudioenergyplus.loadAndTranslateIdf(openstudio.toPath(designDayFilePath))
|
|
226
|
+
if ddyModel.is_initialized():
|
|
227
|
+
ddyModel = ddyModel.get()
|
|
228
|
+
for ddy in ddyModel.getObjectsByType(openstudio.IddObjectType("OS:SizingPeriod:DesignDay")):
|
|
229
|
+
osModel.addObject(ddy.clone())
|
|
230
|
+
else:
|
|
231
|
+
print("EnergyModel.ByTopology - Error: The ddy file is not initialized. Returning None.")
|
|
232
|
+
return None
|
|
233
|
+
|
|
234
|
+
osBuilding = osModel.getBuilding()
|
|
235
|
+
if not floorLevels:
|
|
236
|
+
floorLevels = getFloorLevels(building)
|
|
237
|
+
osBuilding.setStandardsNumberOfStories(len(floorLevels) - 1)
|
|
238
|
+
osBuilding.setNominalFloortoFloorHeight(max(floorLevels) / osBuilding.standardsNumberOfStories().get())
|
|
239
|
+
osBuilding.setDefaultConstructionSet(osModel.getDefaultConstructionSets()[0])
|
|
240
|
+
osBuilding.setDefaultScheduleSet(osModel.getDefaultScheduleSets()[0])
|
|
241
|
+
osBuilding.setName(buildingName)
|
|
242
|
+
osBuilding.setStandardsBuildingType(buildingType)
|
|
243
|
+
osBuilding.setSpaceType(osModel.getSpaceTypeByName(defaultSpaceType).get())
|
|
244
|
+
for storyNumber in range(osBuilding.standardsNumberOfStories().get()):
|
|
245
|
+
osBuildingStory = openstudio.model.BuildingStory(osModel)
|
|
246
|
+
osBuildingStory.setName("STORY_" + str(storyNumber))
|
|
247
|
+
osBuildingStory.setNominalZCoordinate(floorLevels[storyNumber])
|
|
248
|
+
osBuildingStory.setNominalFloortoFloorHeight(osBuilding.nominalFloortoFloorHeight().get())
|
|
249
|
+
osBuilding.setNorthAxis(northAxis)
|
|
250
|
+
|
|
251
|
+
heatingScheduleConstant = openstudio.model.ScheduleConstant(osModel)
|
|
252
|
+
heatingScheduleConstant.setValue(heatingTemp)
|
|
253
|
+
coolingScheduleConstant = openstudio.model.ScheduleConstant(osModel)
|
|
254
|
+
coolingScheduleConstant.setValue(coolingTemp)
|
|
255
|
+
osThermostat = openstudio.model.ThermostatSetpointDualSetpoint(osModel)
|
|
256
|
+
osThermostat.setHeatingSetpointTemperatureSchedule(heatingScheduleConstant)
|
|
257
|
+
osThermostat.setCoolingSetpointTemperatureSchedule(coolingScheduleConstant)
|
|
258
|
+
|
|
259
|
+
osBuildingStorys = list(osModel.getBuildingStorys())
|
|
260
|
+
osBuildingStorys.sort(key=lambda x: x.nominalZCoordinate().get())
|
|
261
|
+
osSpaces = []
|
|
262
|
+
spaceNames = []
|
|
263
|
+
for spaceNumber, buildingCell in enumerate(Topology.SubTopologies(building, "Cell")):
|
|
264
|
+
osSpace = openstudio.model.Space(osModel)
|
|
265
|
+
osSpaceZ = buildingCell.CenterOfMass().Z()
|
|
266
|
+
osBuildingStory = osBuildingStorys[0]
|
|
267
|
+
for x in osBuildingStorys:
|
|
268
|
+
osBuildingStoryZ = x.nominalZCoordinate().get()
|
|
269
|
+
if osBuildingStoryZ + x.nominalFloortoFloorHeight().get() < osSpaceZ:
|
|
270
|
+
continue
|
|
271
|
+
if osBuildingStoryZ < osSpaceZ:
|
|
272
|
+
osBuildingStory = x
|
|
273
|
+
break
|
|
274
|
+
osSpace.setBuildingStory(osBuildingStory)
|
|
275
|
+
cellDictionary = buildingCell.GetDictionary()
|
|
276
|
+
if cellDictionary:
|
|
277
|
+
if spaceTypeKey:
|
|
278
|
+
keyType = getKeyName(cellDictionary, spaceTypeKey)
|
|
279
|
+
else:
|
|
280
|
+
keyType = getKeyName(cellDictionary, 'type')
|
|
281
|
+
if keyType:
|
|
282
|
+
osSpaceTypeName = Dictionary.ValueAtKey(cellDictionary,keyType)
|
|
283
|
+
else:
|
|
284
|
+
osSpaceTypeName = defaultSpaceType
|
|
285
|
+
if osSpaceTypeName:
|
|
286
|
+
sp_ = osModel.getSpaceTypeByName(osSpaceTypeName)
|
|
287
|
+
if sp_.is_initialized():
|
|
288
|
+
osSpace.setSpaceType(sp_.get())
|
|
289
|
+
if spaceNameKey:
|
|
290
|
+
keyName = getKeyName(cellDictionary, spaceNameKey)
|
|
291
|
+
|
|
292
|
+
else:
|
|
293
|
+
keyName = getKeyName(cellDictionary, 'name')
|
|
294
|
+
osSpaceName = None
|
|
295
|
+
if keyName:
|
|
296
|
+
osSpaceName = createUniqueName(Dictionary.ValueAtKey(cellDictionary,keyName),spaceNames, 1)
|
|
297
|
+
if osSpaceName:
|
|
298
|
+
osSpace.setName(osSpaceName)
|
|
299
|
+
else:
|
|
300
|
+
osSpaceName = osBuildingStory.name().get() + "_SPACE_" + str(spaceNumber)
|
|
301
|
+
osSpace.setName(osSpaceName)
|
|
302
|
+
sp_ = osModel.getSpaceTypeByName(defaultSpaceType)
|
|
303
|
+
if sp_.is_initialized():
|
|
304
|
+
osSpace.setSpaceType(sp_.get())
|
|
305
|
+
spaceNames.append(osSpaceName)
|
|
306
|
+
cellFaces = Topology.SubTopologies(buildingCell, "Face")
|
|
307
|
+
if cellFaces:
|
|
308
|
+
for faceNumber, buildingFace in enumerate(cellFaces):
|
|
309
|
+
osFacePoints = []
|
|
310
|
+
for vertex in Topology.SubTopologies(buildingFace.ExternalBoundary(), "Vertex"):
|
|
311
|
+
osFacePoints.append(openstudio.Point3d(vertex.X(), vertex.Y(), vertex.Z()))
|
|
312
|
+
osSurface = openstudio.model.Surface(osFacePoints, osModel)
|
|
313
|
+
faceNormal = topologic.FaceUtility.NormalAtParameters(buildingFace, 0.5, 0.5)
|
|
314
|
+
osFaceNormal = openstudio.Vector3d(faceNormal[0], faceNormal[1], faceNormal[2])
|
|
315
|
+
osFaceNormal.normalize()
|
|
316
|
+
if osFaceNormal.dot(osSurface.outwardNormal()) < 1e-6:
|
|
317
|
+
osSurface.setVertices(list(reversed(osFacePoints)))
|
|
318
|
+
osSurface.setSpace(osSpace)
|
|
319
|
+
faceCells = []
|
|
320
|
+
_ = topologic.FaceUtility.AdjacentCells(buildingFace, building, faceCells)
|
|
321
|
+
if len(faceCells) == 1: #Exterior Surfaces
|
|
322
|
+
osSurface.setOutsideBoundaryCondition("Outdoors")
|
|
323
|
+
if (math.degrees(math.acos(osSurface.outwardNormal().dot(openstudio.Vector3d(0, 0, 1)))) > 135) or (math.degrees(math.acos(osSurface.outwardNormal().dot(openstudio.Vector3d(0, 0, 1)))) < 45):
|
|
324
|
+
osSurface.setSurfaceType("RoofCeiling")
|
|
325
|
+
osSurface.setOutsideBoundaryCondition("Outdoors")
|
|
326
|
+
osSurface.setName(osSpace.name().get() + "_TopHorizontalSlab_" + str(faceNumber))
|
|
327
|
+
if max(list(map(lambda vertex: vertex.Z(), Topology.SubTopologies(buildingFace, "Vertex")))) < 1e-6:
|
|
328
|
+
osSurface.setSurfaceType("Floor")
|
|
329
|
+
osSurface.setOutsideBoundaryCondition("Ground")
|
|
330
|
+
osSurface.setName(osSpace.name().get() + "_BottomHorizontalSlab_" + str(faceNumber))
|
|
331
|
+
else:
|
|
332
|
+
osSurface.setSurfaceType("Wall")
|
|
333
|
+
osSurface.setOutsideBoundaryCondition("Outdoors")
|
|
334
|
+
osSurface.setName(osSpace.name().get() + "_ExternalVerticalFace_" + str(faceNumber))
|
|
335
|
+
# Check for exterior apertures
|
|
336
|
+
faceDictionary = buildingFace.GetDictionary()
|
|
337
|
+
apertures = []
|
|
338
|
+
_ = buildingFace.Apertures(apertures)
|
|
339
|
+
if len(apertures) > 0:
|
|
340
|
+
for aperture in apertures:
|
|
341
|
+
osSubSurfacePoints = []
|
|
342
|
+
#apertureFace = TopologySubTopologies.processItem([aperture, topologic.Face])[0]
|
|
343
|
+
apertureFace = topologic.Aperture.Topology(aperture)
|
|
344
|
+
for vertex in Topology.SubTopologies(apertureFace.ExternalBoundary(), "Vertex"):
|
|
345
|
+
osSubSurfacePoints.append(openstudio.Point3d(vertex.X(), vertex.Y(), vertex.Z()))
|
|
346
|
+
osSubSurface = openstudio.model.SubSurface(osSubSurfacePoints, osModel)
|
|
347
|
+
apertureFaceNormal = topologic.FaceUtility.NormalAtParameters(apertureFace, 0.5, 0.5)
|
|
348
|
+
osSubSurfaceNormal = openstudio.Vector3d(apertureFaceNormal[0], apertureFaceNormal[1], apertureFaceNormal[2])
|
|
349
|
+
osSubSurfaceNormal.normalize()
|
|
350
|
+
if osSubSurfaceNormal.dot(osSubSurface.outwardNormal()) < 1e-6:
|
|
351
|
+
osSubSurface.setVertices(list(reversed(osSubSurfacePoints)))
|
|
352
|
+
osSubSurface.setSubSurfaceType("FixedWindow")
|
|
353
|
+
osSubSurface.setSurface(osSurface)
|
|
354
|
+
else:
|
|
355
|
+
# Get the dictionary keys
|
|
356
|
+
keys = faceDictionary.Keys()
|
|
357
|
+
if ('TOPOLOGIC_glazing_ratio' in keys):
|
|
358
|
+
faceGlazingRatio = Dictionary.ValueAtKey(faceDictionary,'TOPOLOGIC_glazing_ratio')
|
|
359
|
+
if faceGlazingRatio and faceGlazingRatio >= 0.01:
|
|
360
|
+
osSurface.setWindowToWallRatio(faceGlazingRatio)
|
|
361
|
+
else:
|
|
362
|
+
if glazingRatio > 0.01: #Glazing ratio must be more than 1% to make any sense.
|
|
363
|
+
osSurface.setWindowToWallRatio(glazingRatio)
|
|
364
|
+
else: #Interior Surfaces
|
|
365
|
+
if (math.degrees(math.acos(osSurface.outwardNormal().dot(openstudio.Vector3d(0, 0, 1)))) > 135):
|
|
366
|
+
osSurface.setSurfaceType("Floor")
|
|
367
|
+
osSurface.setName(osSpace.name().get() + "_InternalHorizontalFace_" + str(faceNumber))
|
|
368
|
+
elif (math.degrees(math.acos(osSurface.outwardNormal().dot(openstudio.Vector3d(0, 0, 1)))) < 40):
|
|
369
|
+
osSurface.setSurfaceType("RoofCeiling")
|
|
370
|
+
osSurface.setName(osSpace.name().get() + "_InternalHorizontalFace_" + str(faceNumber))
|
|
371
|
+
else:
|
|
372
|
+
osSurface.setSurfaceType("Wall")
|
|
373
|
+
osSurface.setName(osSpace.name().get() + "_InternalVerticalFace_" + str(faceNumber))
|
|
374
|
+
# Check for interior apertures
|
|
375
|
+
faceDictionary = buildingFace.GetDictionary()
|
|
376
|
+
apertures = []
|
|
377
|
+
_ = buildingFace.Apertures(apertures)
|
|
378
|
+
if len(apertures) > 0:
|
|
379
|
+
for aperture in apertures:
|
|
380
|
+
osSubSurfacePoints = []
|
|
381
|
+
#apertureFace = TopologySubTopologies.processItem([aperture, "Face"])[0]
|
|
382
|
+
apertureFace = topologic.Aperture.Topology(aperture)
|
|
383
|
+
for vertex in Topology.SubTopologies(apertureFace.ExternalBoundary(), "Vertex"):
|
|
384
|
+
osSubSurfacePoints.append(openstudio.Point3d(vertex.X(), vertex.Y(), vertex.Z()))
|
|
385
|
+
osSubSurface = openstudio.model.SubSurface(osSubSurfacePoints, osModel)
|
|
386
|
+
apertureFaceNormal = topologic.FaceUtility.NormalAtParameters(apertureFace, 0.5, 0.5)
|
|
387
|
+
osSubSurfaceNormal = openstudio.Vector3d(apertureFaceNormal[0], apertureFaceNormal[1], apertureFaceNormal[2])
|
|
388
|
+
osSubSurfaceNormal.normalize()
|
|
389
|
+
if osSubSurfaceNormal.dot(osSubSurface.outwardNormal()) < 1e-6:
|
|
390
|
+
osSubSurface.setVertices(list(reversed(osSubSurfacePoints)))
|
|
391
|
+
osSubSurface.setSubSurfaceType("Door") #We are assuming all interior apertures to be doors
|
|
392
|
+
osSubSurface.setSurface(osSurface)
|
|
393
|
+
|
|
394
|
+
osThermalZone = openstudio.model.ThermalZone(osModel)
|
|
395
|
+
osThermalZone.setVolume(topologic.CellUtility.Volume(buildingCell))
|
|
396
|
+
osThermalZone.setName(osSpace.name().get() + "_THERMAL_ZONE")
|
|
397
|
+
osThermalZone.setUseIdealAirLoads(True)
|
|
398
|
+
osThermalZone.setVolume(topologic.CellUtility.Volume(buildingCell))
|
|
399
|
+
osThermalZone.setThermostatSetpointDualSetpoint(osThermostat)
|
|
400
|
+
osSpace.setThermalZone(osThermalZone)
|
|
401
|
+
|
|
402
|
+
for x in osSpaces:
|
|
403
|
+
if osSpace.boundingBox().intersects(x.boundingBox()):
|
|
404
|
+
osSpace.matchSurfaces(x)
|
|
405
|
+
osSpaces.append(osSpace)
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
if shadingSurfaces:
|
|
409
|
+
osShadingGroup = openstudio.model.ShadingSurfaceGroup(osModel)
|
|
410
|
+
for faceIndex, shadingFace in enumerate(Topology.SubTopologies(shadingSurfaces, "Face")):
|
|
411
|
+
facePoints = []
|
|
412
|
+
for aVertex in Topology.SubTopologies(shadingFace.ExternalBoundary(), "Vertex"):
|
|
413
|
+
facePoints.append(openstudio.Point3d(aVertex.X(), aVertex.Y(), aVertex.Z()))
|
|
414
|
+
aShadingSurface = openstudio.model.ShadingSurface(facePoints, osModel)
|
|
415
|
+
faceNormal = topologic.FaceUtility.NormalAtParameters(shadingFace, 0.5, 0.5)
|
|
416
|
+
osFaceNormal = openstudio.Vector3d(faceNormal[0], faceNormal[1], faceNormal[2])
|
|
417
|
+
osFaceNormal.normalize()
|
|
418
|
+
if osFaceNormal.dot(aShadingSurface.outwardNormal()) < 0:
|
|
419
|
+
aShadingSurface.setVertices(list(reversed(facePoints)))
|
|
420
|
+
aShadingSurface.setName("SHADINGSURFACE_" + str(faceIndex))
|
|
421
|
+
aShadingSurface.setShadingSurfaceGroup(osShadingGroup)
|
|
422
|
+
|
|
423
|
+
osModel.purgeUnusedResourceObjects()
|
|
424
|
+
return osModel
|
|
425
|
+
|
|
426
|
+
@staticmethod
|
|
427
|
+
def ColumnNames(model, reportName, tableName):
|
|
428
|
+
"""
|
|
429
|
+
Returns the list of column names given an OSM model, report name, and table name.
|
|
430
|
+
|
|
431
|
+
Parameters
|
|
432
|
+
----------
|
|
433
|
+
model : openstudio.openstudiomodelcore.Model
|
|
434
|
+
The input OSM model.
|
|
435
|
+
reportName : str
|
|
436
|
+
The input report name.
|
|
437
|
+
tableName : str
|
|
438
|
+
The input table name.
|
|
439
|
+
|
|
440
|
+
Returns
|
|
441
|
+
-------
|
|
442
|
+
list
|
|
443
|
+
the list of column names.
|
|
444
|
+
|
|
445
|
+
"""
|
|
446
|
+
sql = model.sqlFile().get()
|
|
447
|
+
query = "SELECT ColumnName FROM tabulardatawithstrings WHERE ReportName = '"+reportName+"' AND TableName = '"+tableName+"'"
|
|
448
|
+
columnNames = sql.execAndReturnVectorOfString(query).get()
|
|
449
|
+
return list(OrderedDict( (x,1) for x in columnNames ).keys()) #Making a unique list and keeping its order
|
|
450
|
+
|
|
451
|
+
@staticmethod
|
|
452
|
+
def DefaultConstructionSets(model):
|
|
453
|
+
"""
|
|
454
|
+
Returns the default construction sets in the input OSM model.
|
|
455
|
+
|
|
456
|
+
Parameters
|
|
457
|
+
----------
|
|
458
|
+
model : openstudio.openstudiomodelcore.Model
|
|
459
|
+
The input OSM model.
|
|
460
|
+
|
|
461
|
+
Returns
|
|
462
|
+
-------
|
|
463
|
+
list
|
|
464
|
+
The default construction sets.
|
|
465
|
+
|
|
466
|
+
"""
|
|
467
|
+
sets = model.getDefaultConstructionSets()
|
|
468
|
+
names = []
|
|
469
|
+
for aSet in sets:
|
|
470
|
+
names.append(aSet.name().get())
|
|
471
|
+
return [sets, names]
|
|
472
|
+
|
|
473
|
+
@staticmethod
|
|
474
|
+
def DefaultScheduleSets(model):
|
|
475
|
+
"""
|
|
476
|
+
Returns the default schedule sets found in the input OSM model.
|
|
477
|
+
|
|
478
|
+
Parameters
|
|
479
|
+
----------
|
|
480
|
+
model : openstudio.openstudiomodelcore.Model
|
|
481
|
+
The input OSM model.
|
|
482
|
+
|
|
483
|
+
Returns
|
|
484
|
+
-------
|
|
485
|
+
list
|
|
486
|
+
The list of default schedule sets.
|
|
487
|
+
|
|
488
|
+
"""
|
|
489
|
+
sets = model.getDefaultScheduleSets()
|
|
490
|
+
names = []
|
|
491
|
+
for aSet in sets:
|
|
492
|
+
names.append(aSet.name().get())
|
|
493
|
+
return [sets, names]
|
|
494
|
+
|
|
495
|
+
@staticmethod
|
|
496
|
+
def ExportToGbXML(model, path, overwrite=False):
|
|
497
|
+
"""
|
|
498
|
+
Exports the input OSM model to a gbxml file.
|
|
499
|
+
|
|
500
|
+
Parameters
|
|
501
|
+
----------
|
|
502
|
+
model : openstudio.openstudiomodelcore.Model
|
|
503
|
+
The input OSM model.
|
|
504
|
+
path : str
|
|
505
|
+
The path for saving the file.
|
|
506
|
+
overwrite : bool, optional
|
|
507
|
+
If set to True any file with the same name is over-written. The default is False.
|
|
508
|
+
|
|
509
|
+
Returns
|
|
510
|
+
-------
|
|
511
|
+
bool
|
|
512
|
+
True if the file is written successfully. False otherwise.
|
|
513
|
+
|
|
514
|
+
"""
|
|
515
|
+
ext = path[len(path)-4:len(path)]
|
|
516
|
+
if ext.lower() != ".xml":
|
|
517
|
+
path = path+".xml"
|
|
518
|
+
if(exists(path) and (overwrite == False)):
|
|
519
|
+
print("EnergyModel.ExportToGbXML - Error: Could not export the file because it already exists and overwrite is set to False. Returning None.")
|
|
520
|
+
return None
|
|
521
|
+
return openstudio.gbxml.GbXMLForwardTranslator().modelToGbXML(model, openstudio.openstudioutilitiescore.toPath(path))
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
@staticmethod
|
|
525
|
+
def ExportToOSM(model, path, overwrite=False):
|
|
526
|
+
"""
|
|
527
|
+
Exports the input OSM model to an OSM file.
|
|
528
|
+
|
|
529
|
+
Parameters
|
|
530
|
+
----------
|
|
531
|
+
model : openstudio.openstudiomodelcore.Model
|
|
532
|
+
The input OSM model.
|
|
533
|
+
path : str
|
|
534
|
+
The path for saving the file.
|
|
535
|
+
overwrite : bool, optional
|
|
536
|
+
If set to True any file with the same name is over-written. The default is False.
|
|
537
|
+
|
|
538
|
+
Returns
|
|
539
|
+
-------
|
|
540
|
+
bool
|
|
541
|
+
True if the file is written successfully. False otherwise.
|
|
542
|
+
|
|
543
|
+
"""
|
|
544
|
+
ext = path[len(path)-4:len(path)]
|
|
545
|
+
if ext.lower() != ".osm":
|
|
546
|
+
path = path+".osm"
|
|
547
|
+
osCondition = False
|
|
548
|
+
osPath = openstudio.openstudioutilitiescore.toPath(path)
|
|
549
|
+
osCondition = model.save(osPath, overwrite)
|
|
550
|
+
return osCondition
|
|
551
|
+
|
|
552
|
+
@staticmethod
|
|
553
|
+
def GbXMLString(model):
|
|
554
|
+
"""
|
|
555
|
+
Returns the gbxml string of the input OSM model.
|
|
556
|
+
|
|
557
|
+
Parameters
|
|
558
|
+
----------
|
|
559
|
+
model : openstudio.openstudiomodelcore.Model
|
|
560
|
+
The input OSM model.
|
|
561
|
+
|
|
562
|
+
Returns
|
|
563
|
+
-------
|
|
564
|
+
str
|
|
565
|
+
The gbxml string.
|
|
566
|
+
|
|
567
|
+
"""
|
|
568
|
+
return openstudio.gbxml.GbXMLForwardTranslator().modelToGbXMLString(model)
|
|
569
|
+
|
|
570
|
+
@staticmethod
|
|
571
|
+
def Query(model,
|
|
572
|
+
reportName : str = "HVACSizingSummary",
|
|
573
|
+
reportForString : str = "Entire Facility",
|
|
574
|
+
tableName : str = "Zone Sensible Cooling",
|
|
575
|
+
columnName : str = "Calculated Design Load",
|
|
576
|
+
rowNames : list = [],
|
|
577
|
+
units : str = "W"):
|
|
578
|
+
"""
|
|
579
|
+
Queries the model for values.
|
|
580
|
+
|
|
581
|
+
Parameters
|
|
582
|
+
----------
|
|
583
|
+
model : openstudio.openstudiomodelcore.Model
|
|
584
|
+
The input OSM model.
|
|
585
|
+
reportName : str , optional
|
|
586
|
+
The input report name. The default is "HVACSizingSummary".
|
|
587
|
+
reportForString : str, optional
|
|
588
|
+
The input report for string. The default is "Entire Facility".
|
|
589
|
+
tableName : str , optional
|
|
590
|
+
The input table name. The default is "Zone Sensible Cooling".
|
|
591
|
+
columnName : str , optional
|
|
592
|
+
The input column name. The default is "Calculated Design Load".
|
|
593
|
+
rowNames : list , optional
|
|
594
|
+
The input list of row names. The default is [].
|
|
595
|
+
units : str , optional
|
|
596
|
+
The input units. The default is "W".
|
|
597
|
+
|
|
598
|
+
Returns
|
|
599
|
+
-------
|
|
600
|
+
list
|
|
601
|
+
The list of values.
|
|
602
|
+
|
|
603
|
+
"""
|
|
604
|
+
|
|
605
|
+
def doubleValueFromQuery(sqlFile, reportName, reportForString,
|
|
606
|
+
tableName, columnName, rowName,
|
|
607
|
+
units):
|
|
608
|
+
query = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='" + reportName + "' AND ReportForString='" + reportForString + "' AND TableName = '" + tableName + "' AND RowName = '" + rowName + "' AND ColumnName= '" + columnName + "' AND Units='" + units + "'";
|
|
609
|
+
osOptionalDoubleValue = sqlFile.execAndReturnFirstDouble(query)
|
|
610
|
+
if (osOptionalDoubleValue.is_initialized()):
|
|
611
|
+
return osOptionalDoubleValue.get()
|
|
612
|
+
else:
|
|
613
|
+
return None
|
|
614
|
+
|
|
615
|
+
sqlFile = model.sqlFile().get()
|
|
616
|
+
returnValues = []
|
|
617
|
+
for rowName in rowNames:
|
|
618
|
+
returnValues.append(doubleValueFromQuery(sqlFile, reportName, reportForString, tableName, columnName, rowName, units))
|
|
619
|
+
return returnValues
|
|
620
|
+
|
|
621
|
+
@staticmethod
|
|
622
|
+
def ReportNames(model):
|
|
623
|
+
"""
|
|
624
|
+
Returns the report names found in the input OSM model.
|
|
625
|
+
|
|
626
|
+
Parameters
|
|
627
|
+
----------
|
|
628
|
+
model : openstudio.openstudiomodelcore.Model
|
|
629
|
+
The input OSM model.
|
|
630
|
+
|
|
631
|
+
Returns
|
|
632
|
+
-------
|
|
633
|
+
list
|
|
634
|
+
The list of report names found in the input OSM model.
|
|
635
|
+
|
|
636
|
+
"""
|
|
637
|
+
sql = model.sqlFile().get()
|
|
638
|
+
reportNames = sql.execAndReturnVectorOfString("SELECT ReportName FROM tabulardatawithstrings").get()
|
|
639
|
+
return list(OrderedDict( (x,1) for x in reportNames ).keys()) #Making a unique list and keeping its order
|
|
640
|
+
|
|
641
|
+
@staticmethod
|
|
642
|
+
def RowNames(model, reportName, tableName):
|
|
643
|
+
"""
|
|
644
|
+
Returns the list of row names given an OSM model, report name, and table name.
|
|
645
|
+
|
|
646
|
+
Parameters
|
|
647
|
+
----------
|
|
648
|
+
model : openstudio.openstudiomodelcore.Model
|
|
649
|
+
The input OSM model.
|
|
650
|
+
reportName : str
|
|
651
|
+
The input name of the report.
|
|
652
|
+
tableName : str
|
|
653
|
+
The input name of the table.
|
|
654
|
+
|
|
655
|
+
Returns
|
|
656
|
+
-------
|
|
657
|
+
list
|
|
658
|
+
The list of row names.
|
|
659
|
+
|
|
660
|
+
"""
|
|
661
|
+
sql = model.sqlFile().get()
|
|
662
|
+
query = "SELECT RowName FROM tabulardatawithstrings WHERE ReportName = '"+reportName+"' AND TableName = '"+tableName+"'"
|
|
663
|
+
columnNames = sql.execAndReturnVectorOfString(query).get()
|
|
664
|
+
return list(OrderedDict( (x,1) for x in columnNames ).keys()) #Making a unique list and keeping its order
|
|
665
|
+
|
|
666
|
+
@staticmethod
|
|
667
|
+
def Run(model, weatherFilePath: str = None, osBinaryPath : str = None, outputFolder : str = None):
|
|
668
|
+
"""
|
|
669
|
+
Runs an energy simulation.
|
|
670
|
+
|
|
671
|
+
Parameters
|
|
672
|
+
----------
|
|
673
|
+
model : openstudio.openstudiomodelcore.Model
|
|
674
|
+
The input OSM model.
|
|
675
|
+
weatherFilePath : str
|
|
676
|
+
The path to the epw weather file.
|
|
677
|
+
osBinaryPath : str
|
|
678
|
+
The path to the openstudio binary.
|
|
679
|
+
outputFolder : str
|
|
680
|
+
The path to the output folder.
|
|
681
|
+
|
|
682
|
+
Returns
|
|
683
|
+
-------
|
|
684
|
+
model : openstudio.openstudiomodelcore.Model
|
|
685
|
+
The simulated OSM model.
|
|
686
|
+
|
|
687
|
+
"""
|
|
688
|
+
import os
|
|
689
|
+
if not weatherFilePath:
|
|
690
|
+
weatherFilePath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "assets", "EnergyModel", "GBR_London.Gatwick.037760_IWEC.epw")
|
|
691
|
+
pbar = tqdm(desc='Running Simulation', total=100, leave=False)
|
|
692
|
+
utcnow = datetime.utcnow()
|
|
693
|
+
timestamp = utcnow.strftime("UTC-%Y-%m-%d-%H-%M-%S")
|
|
694
|
+
if not outputFolder:
|
|
695
|
+
home = os.path.expanduser('~')
|
|
696
|
+
outputFolder = os.path.join(home, "EnergyModels", timestamp)
|
|
697
|
+
else:
|
|
698
|
+
outputFolder = os.path.join(outputFolder, timestamp)
|
|
699
|
+
os.mkdir(outputFolder)
|
|
700
|
+
pbar.update(10)
|
|
701
|
+
osmPath = os.path.join(outputFolder, model.getBuilding().name().get() + ".osm")
|
|
702
|
+
model.save(openstudio.openstudioutilitiescore.toPath(osmPath), True)
|
|
703
|
+
oswPath = os.path.join(outputFolder, model.getBuilding().name().get() + ".osw")
|
|
704
|
+
pbar.update(20)
|
|
705
|
+
#print("oswPath = "+oswPath)
|
|
706
|
+
workflow = model.workflowJSON()
|
|
707
|
+
workflow.setSeedFile(openstudio.openstudioutilitiescore.toPath(osmPath))
|
|
708
|
+
pbar.update(30)
|
|
709
|
+
#print("Seed File Set")
|
|
710
|
+
workflow.setWeatherFile(openstudio.openstudioutilitiescore.toPath(weatherFilePath))
|
|
711
|
+
pbar.update(40)
|
|
712
|
+
#print("Weather File Set")
|
|
713
|
+
workflow.saveAs(openstudio.openstudioutilitiescore.toPath(oswPath))
|
|
714
|
+
pbar.update(50)
|
|
715
|
+
#print("OSW File Saved")
|
|
716
|
+
cmd = osBinaryPath+" run -w " + "\"" + oswPath + "\""
|
|
717
|
+
pbar.update(60)
|
|
718
|
+
os.system(cmd)
|
|
719
|
+
#print("Simulation DONE")
|
|
720
|
+
sqlPath = os.path.join(os.path.join(outputFolder,"run"), "eplusout.sql")
|
|
721
|
+
pbar.update(100)
|
|
722
|
+
#print("sqlPath = "+sqlPath)
|
|
723
|
+
osSqlFile = openstudio.SqlFile(openstudio.openstudioutilitiescore.toPath(sqlPath))
|
|
724
|
+
model.setSqlFile(osSqlFile)
|
|
725
|
+
pbar.close()
|
|
726
|
+
return model
|
|
727
|
+
|
|
728
|
+
@staticmethod
|
|
729
|
+
def SpaceDictionaries(model):
|
|
730
|
+
"""
|
|
731
|
+
Return the space dictionaries found in the input OSM model.
|
|
732
|
+
|
|
733
|
+
Parameters
|
|
734
|
+
----------
|
|
735
|
+
model : openstudio.openstudiomodelcore.Model
|
|
736
|
+
The input OSM model.
|
|
737
|
+
|
|
738
|
+
Returns
|
|
739
|
+
-------
|
|
740
|
+
dict
|
|
741
|
+
The dictionary of space types, names, and colors found in the input OSM model. The dictionary has the following keys:
|
|
742
|
+
- "types"
|
|
743
|
+
- "names"
|
|
744
|
+
- "colors"
|
|
745
|
+
|
|
746
|
+
"""
|
|
747
|
+
types = model.getSpaceTypes()
|
|
748
|
+
names = []
|
|
749
|
+
colors = []
|
|
750
|
+
for aType in types:
|
|
751
|
+
names.append(aType.name().get())
|
|
752
|
+
red = aType.renderingColor().get().renderingRedValue()
|
|
753
|
+
green = aType.renderingColor().get().renderingGreenValue()
|
|
754
|
+
blue = aType.renderingColor().get().renderingBlueValue()
|
|
755
|
+
colors.append([red,green,blue])
|
|
756
|
+
return {'types': types, 'names': names, 'colors': colors}
|
|
757
|
+
|
|
758
|
+
@staticmethod
|
|
759
|
+
def SpaceTypes(model):
|
|
760
|
+
"""
|
|
761
|
+
Return the space types found in the input OSM model.
|
|
762
|
+
|
|
763
|
+
Parameters
|
|
764
|
+
----------
|
|
765
|
+
model : openstudio.openstudiomodelcore.Model
|
|
766
|
+
The input OSM model.
|
|
767
|
+
|
|
768
|
+
Returns
|
|
769
|
+
-------
|
|
770
|
+
list
|
|
771
|
+
The list of space types
|
|
772
|
+
|
|
773
|
+
"""
|
|
774
|
+
return model.getSpaceTypes()
|
|
775
|
+
|
|
776
|
+
@staticmethod
|
|
777
|
+
def SpaceTypeNames(model):
|
|
778
|
+
"""
|
|
779
|
+
Return the space type names found in the input OSM model.
|
|
780
|
+
|
|
781
|
+
Parameters
|
|
782
|
+
----------
|
|
783
|
+
model : openstudio.openstudiomodelcore.Model
|
|
784
|
+
The input OSM model.
|
|
785
|
+
|
|
786
|
+
Returns
|
|
787
|
+
-------
|
|
788
|
+
list
|
|
789
|
+
The list of space type names
|
|
790
|
+
|
|
791
|
+
"""
|
|
792
|
+
types = model.getSpaceTypes()
|
|
793
|
+
names = []
|
|
794
|
+
colors = []
|
|
795
|
+
for aType in types:
|
|
796
|
+
names.append(aType.name().get())
|
|
797
|
+
return names
|
|
798
|
+
|
|
799
|
+
@staticmethod
|
|
800
|
+
def SpaceColors(model):
|
|
801
|
+
"""
|
|
802
|
+
Return the space colors found in the input OSM model.
|
|
803
|
+
|
|
804
|
+
Parameters
|
|
805
|
+
----------
|
|
806
|
+
model : openstudio.openstudiomodelcore.Model
|
|
807
|
+
The input OSM model.
|
|
808
|
+
|
|
809
|
+
Returns
|
|
810
|
+
-------
|
|
811
|
+
list
|
|
812
|
+
The list of space colors. Each item is a three-item list representing the red, green, and blue values of the color.
|
|
813
|
+
|
|
814
|
+
"""
|
|
815
|
+
types = model.getSpaceTypes()
|
|
816
|
+
colors = []
|
|
817
|
+
for aType in types:
|
|
818
|
+
red = aType.renderingColor().get().renderingRedValue()
|
|
819
|
+
green = aType.renderingColor().get().renderingGreenValue()
|
|
820
|
+
blue = aType.renderingColor().get().renderingBlueValue()
|
|
821
|
+
colors.append([red,green,blue])
|
|
822
|
+
return colors
|
|
823
|
+
|
|
824
|
+
@staticmethod
|
|
825
|
+
def SqlFile(model):
|
|
826
|
+
"""
|
|
827
|
+
Returns the SQL file found in the input OSM model.
|
|
828
|
+
|
|
829
|
+
Parameters
|
|
830
|
+
----------
|
|
831
|
+
model : openstudio.openstudiomodelcore.Model
|
|
832
|
+
The input OSM model.
|
|
833
|
+
|
|
834
|
+
Returns
|
|
835
|
+
-------
|
|
836
|
+
SQL file
|
|
837
|
+
The SQL file found in the input OSM model.
|
|
838
|
+
|
|
839
|
+
"""
|
|
840
|
+
return model.sqlFile().get()
|
|
841
|
+
|
|
842
|
+
@staticmethod
|
|
843
|
+
def TableNames(model, reportName):
|
|
844
|
+
"""
|
|
845
|
+
Returns the table names found in the input OSM model and report name.
|
|
846
|
+
|
|
847
|
+
Parameters
|
|
848
|
+
----------
|
|
849
|
+
model : openstudio.openstudiomodelcore.Model
|
|
850
|
+
The input OSM model.
|
|
851
|
+
reportName : str
|
|
852
|
+
The input report name.
|
|
853
|
+
|
|
854
|
+
Returns
|
|
855
|
+
-------
|
|
856
|
+
list
|
|
857
|
+
The list of table names found in the input OSM model and report name.
|
|
858
|
+
|
|
859
|
+
"""
|
|
860
|
+
sql = model.sqlFile().get()
|
|
861
|
+
tableNames = sql.execAndReturnVectorOfString("SELECT TableName FROM tabulardatawithstrings WHERE ReportName='"+reportName+"'").get()
|
|
862
|
+
return list(OrderedDict( (x,1) for x in tableNames ).keys()) #Making a unique list and keeping its order
|
|
863
|
+
|
|
864
|
+
@staticmethod
|
|
865
|
+
def Topologies(model):
|
|
866
|
+
"""
|
|
867
|
+
Parameters
|
|
868
|
+
----------
|
|
869
|
+
model : openstudio.openstudiomodelcore.Model
|
|
870
|
+
The input OSM model.
|
|
871
|
+
|
|
872
|
+
Returns
|
|
873
|
+
-------
|
|
874
|
+
dict
|
|
875
|
+
The dictionary of topologies found in the input OSM model. The keys of the dictionary are:
|
|
876
|
+
- "cells"
|
|
877
|
+
- "apertures"
|
|
878
|
+
- "shadingFaces"
|
|
879
|
+
|
|
880
|
+
"""
|
|
881
|
+
from topologicpy.Edge import Edge
|
|
882
|
+
from topologicpy.Wire import Wire
|
|
883
|
+
from topologicpy.Face import Face
|
|
884
|
+
from topologicpy.Shell import Shell
|
|
885
|
+
from topologicpy.Cell import Cell
|
|
886
|
+
from topologicpy.Cluster import Cluster
|
|
887
|
+
from topologicpy.Dictionary import Dictionary
|
|
888
|
+
from topologicpy.Topology import Topology
|
|
889
|
+
|
|
890
|
+
def surfaceToFace(surface):
|
|
891
|
+
surfaceEdges = []
|
|
892
|
+
surfaceVertices = surface.vertices()
|
|
893
|
+
for i in range(len(surfaceVertices)-1):
|
|
894
|
+
sv = topologic.Vertex.ByCoordinates(surfaceVertices[i].x(), surfaceVertices[i].y(), surfaceVertices[i].z())
|
|
895
|
+
ev = topologic.Vertex.ByCoordinates(surfaceVertices[i+1].x(), surfaceVertices[i+1].y(), surfaceVertices[i+1].z())
|
|
896
|
+
edge = Edge.ByStartVertexEndVertex(sv, ev)
|
|
897
|
+
if not edge:
|
|
898
|
+
continue
|
|
899
|
+
surfaceEdges.append(edge)
|
|
900
|
+
sv = topologic.Vertex.ByCoordinates(surfaceVertices[len(surfaceVertices)-1].x(), surfaceVertices[len(surfaceVertices)-1].y(), surfaceVertices[len(surfaceVertices)-1].z())
|
|
901
|
+
ev = topologic.Vertex.ByCoordinates(surfaceVertices[0].x(), surfaceVertices[0].y(), surfaceVertices[0].z())
|
|
902
|
+
edge = Edge.ByStartVertexEndVertex(sv, ev)
|
|
903
|
+
surfaceEdges.append(edge)
|
|
904
|
+
surfaceWire = Wire.ByEdges(surfaceEdges)
|
|
905
|
+
internalBoundaries = []
|
|
906
|
+
surfaceFace = Face.ByWires(surfaceWire, internalBoundaries)
|
|
907
|
+
return surfaceFace
|
|
908
|
+
|
|
909
|
+
def addApertures(face, apertures):
|
|
910
|
+
usedFaces = []
|
|
911
|
+
for aperture in apertures:
|
|
912
|
+
cen = aperture.CenterOfMass()
|
|
913
|
+
try:
|
|
914
|
+
params = face.ParametersAtVertex(cen)
|
|
915
|
+
u = params[0]
|
|
916
|
+
v = params[1]
|
|
917
|
+
w = 0.5
|
|
918
|
+
except:
|
|
919
|
+
u = 0.5
|
|
920
|
+
v = 0.5
|
|
921
|
+
w = 0.5
|
|
922
|
+
context = topologic.Context.ByTopologyParameters(face, u, v, w)
|
|
923
|
+
_ = topologic.Aperture.ByTopologyContext(aperture, context)
|
|
924
|
+
return face
|
|
925
|
+
spaces = list(model.getSpaces())
|
|
926
|
+
|
|
927
|
+
vertexIndex = 0
|
|
928
|
+
cells = []
|
|
929
|
+
apertures = []
|
|
930
|
+
shadingFaces = []
|
|
931
|
+
shadingSurfaces = list(model.getShadingSurfaces())
|
|
932
|
+
|
|
933
|
+
for aShadingSurface in shadingSurfaces:
|
|
934
|
+
shadingFace = surfaceToFace(aShadingSurface)
|
|
935
|
+
if aShadingSurface.shadingSurfaceGroup().is_initialized():
|
|
936
|
+
shadingGroup = aShadingSurface.shadingSurfaceGroup().get()
|
|
937
|
+
if shadingGroup.space().is_initialized():
|
|
938
|
+
space = shadingGroup.space().get()
|
|
939
|
+
osTransformation = space.transformation()
|
|
940
|
+
osTranslation = osTransformation.translation()
|
|
941
|
+
osMatrix = osTransformation.rotationMatrix()
|
|
942
|
+
rotation11 = osMatrix[0, 0]
|
|
943
|
+
rotation12 = osMatrix[0, 1]
|
|
944
|
+
rotation13 = osMatrix[0, 2]
|
|
945
|
+
rotation21 = osMatrix[1, 0]
|
|
946
|
+
rotation22 = osMatrix[1, 1]
|
|
947
|
+
rotation23 = osMatrix[1, 2]
|
|
948
|
+
rotation31 = osMatrix[2, 0]
|
|
949
|
+
rotation32 = osMatrix[2, 1]
|
|
950
|
+
rotation33 = osMatrix[2, 2]
|
|
951
|
+
shadingFace = topologic.TopologyUtility.Transform(shadingFace, osTranslation.x(), osTranslation.y(), osTranslation.z(), rotation11, rotation12, rotation13, rotation21, rotation22, rotation23, rotation31, rotation32, rotation33)
|
|
952
|
+
shadingFaces.append(shadingFace)
|
|
953
|
+
|
|
954
|
+
for count, aSpace in enumerate(spaces):
|
|
955
|
+
osTransformation = aSpace.transformation()
|
|
956
|
+
osTranslation = osTransformation.translation()
|
|
957
|
+
osMatrix = osTransformation.rotationMatrix()
|
|
958
|
+
rotation11 = osMatrix[0, 0]
|
|
959
|
+
rotation12 = osMatrix[0, 1]
|
|
960
|
+
rotation13 = osMatrix[0, 2]
|
|
961
|
+
rotation21 = osMatrix[1, 0]
|
|
962
|
+
rotation22 = osMatrix[1, 1]
|
|
963
|
+
rotation23 = osMatrix[1, 2]
|
|
964
|
+
rotation31 = osMatrix[2, 0]
|
|
965
|
+
rotation32 = osMatrix[2, 1]
|
|
966
|
+
rotation33 = osMatrix[2, 2]
|
|
967
|
+
spaceFaces = []
|
|
968
|
+
surfaces = aSpace.surfaces()
|
|
969
|
+
|
|
970
|
+
for aSurface in surfaces:
|
|
971
|
+
aFace = surfaceToFace(aSurface)
|
|
972
|
+
aFace = topologic.TopologyUtility.Transform(aFace, osTranslation.x(), osTranslation.y(), osTranslation.z(), rotation11, rotation12, rotation13, rotation21, rotation22, rotation23, rotation31, rotation32, rotation33)
|
|
973
|
+
#aFace.__class__ = topologic.Face
|
|
974
|
+
subSurfaces = aSurface.subSurfaces()
|
|
975
|
+
for aSubSurface in subSurfaces:
|
|
976
|
+
aperture = surfaceToFace(aSubSurface)
|
|
977
|
+
aperture = topologic.TopologyUtility.Transform(aperture, osTranslation.x(), osTranslation.y(), osTranslation.z(), rotation11, rotation12, rotation13, rotation21, rotation22, rotation23, rotation31, rotation32, rotation33)
|
|
978
|
+
# aperture.__class__ = topologic.Face
|
|
979
|
+
apertures.append(aperture)
|
|
980
|
+
addApertures(aFace, apertures)
|
|
981
|
+
spaceFaces.append(aFace)
|
|
982
|
+
spaceFaces = [x for x in spaceFaces if isinstance(x, topologic.Face)]
|
|
983
|
+
spaceCell = Cell.ByFaces(spaceFaces)
|
|
984
|
+
if not spaceCell:
|
|
985
|
+
spaceCell = Shell.ByFaces(spaceFaces)
|
|
986
|
+
if not spaceCell:
|
|
987
|
+
spaceCell = Cluster.ByTopologies(spaceFaces)
|
|
988
|
+
if spaceCell: #debugging
|
|
989
|
+
# Set Dictionary for Cell
|
|
990
|
+
keys = []
|
|
991
|
+
values = []
|
|
992
|
+
|
|
993
|
+
keys.append("TOPOLOGIC_id")
|
|
994
|
+
keys.append("TOPOLOGIC_name")
|
|
995
|
+
keys.append("TOPOLOGIC_type")
|
|
996
|
+
keys.append("TOPOLOGIC_color")
|
|
997
|
+
spaceID = str(aSpace.handle()).replace('{','').replace('}','')
|
|
998
|
+
values.append(spaceID)
|
|
999
|
+
values.append(aSpace.name().get())
|
|
1000
|
+
spaceTypeName = "Unknown"
|
|
1001
|
+
red = 255
|
|
1002
|
+
green = 255
|
|
1003
|
+
blue = 255
|
|
1004
|
+
|
|
1005
|
+
if (aSpace.spaceType().is_initialized()):
|
|
1006
|
+
if(aSpace.spaceType().get().name().is_initialized()):
|
|
1007
|
+
spaceTypeName = aSpace.spaceType().get().name().get()
|
|
1008
|
+
if(aSpace.spaceType().get().renderingColor().is_initialized()):
|
|
1009
|
+
red = aSpace.spaceType().get().renderingColor().get().renderingRedValue()
|
|
1010
|
+
green = aSpace.spaceType().get().renderingColor().get().renderingGreenValue()
|
|
1011
|
+
blue = aSpace.spaceType().get().renderingColor().get().renderingBlueValue()
|
|
1012
|
+
values.append(spaceTypeName)
|
|
1013
|
+
values.append([red, green, blue])
|
|
1014
|
+
d = Dictionary.ByKeysValues(keys, values)
|
|
1015
|
+
spaceCell = Topology.SetDictionary(spaceCell, d)
|
|
1016
|
+
cells.append(spaceCell)
|
|
1017
|
+
return {'cells':cells, 'apertures':apertures, 'shadingFaces': shadingFaces}
|
|
1018
|
+
|
|
1019
|
+
@staticmethod
|
|
1020
|
+
def Units(model, reportName, tableName, columnName):
|
|
1021
|
+
"""
|
|
1022
|
+
Parameters
|
|
1023
|
+
----------
|
|
1024
|
+
model : openstudio.openstudiomodelcore.Model
|
|
1025
|
+
The input OSM model.
|
|
1026
|
+
reportName : str
|
|
1027
|
+
The input report name.
|
|
1028
|
+
tableName : str
|
|
1029
|
+
The input table name.
|
|
1030
|
+
columnName : str
|
|
1031
|
+
The input column name.
|
|
1032
|
+
|
|
1033
|
+
Returns
|
|
1034
|
+
-------
|
|
1035
|
+
str
|
|
1036
|
+
The units string found in the input OSM model, report name, table name, and column name.
|
|
1037
|
+
|
|
1038
|
+
"""
|
|
1039
|
+
# model = item[0]
|
|
1040
|
+
# reportName = item[1]
|
|
1041
|
+
# tableName = item[2]
|
|
1042
|
+
# columnName = item[3]
|
|
1043
|
+
sql = model.sqlFile().get()
|
|
1044
|
+
query = "SELECT Units FROM tabulardatawithstrings WHERE ReportName = '"+reportName+"' AND TableName = '"+tableName+"' AND ColumnName = '"+columnName+"'"
|
|
1045
|
+
units = sql.execAndReturnFirstString(query)
|
|
1046
|
+
if (units.is_initialized()):
|
|
1047
|
+
units = units.get()
|
|
1048
|
+
else:
|
|
1049
|
+
print("EnergyModel.Units - Error: Could not retrieve the units. Returning None.")
|
|
1050
|
+
return None
|
|
1051
|
+
return units
|
|
1052
|
+
|