dragonfly-trace 0.1.0__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.
@@ -0,0 +1 @@
1
+ """dragonfly-trace package."""
@@ -0,0 +1,4 @@
1
+ from dragonfly_trace.cli import trace
2
+
3
+ if __name__ == '__main__':
4
+ trace()
@@ -0,0 +1,157 @@
1
+ # coding=utf-8
2
+ """Methods to write room airflows to matrices for Trane TRACE tables."""
3
+ from __future__ import division
4
+
5
+ from ladybug.datatype.volumeflowrate import VolumeFlowRate
6
+ from ladybug.datatype.volumeflowrateintensity import VolumeFlowRateIntensity
7
+
8
+
9
+ def airflows_trace700_matrix(rooms, si_units=False):
10
+ """Get a matrix for the "Airflows" table of the TRACE 700 Component Tree.
11
+
12
+ Args:
13
+ rooms: A list of dragonfly Room2Ds and honeybee Rooms for which the
14
+ TRACE 700 "Airflows" matrix will be returned.
15
+ si_units: Boolean to note whether the units of the values in the resulting
16
+ matrix are in SI (True) instead of IP (False). (Default: False).
17
+
18
+ Returns:
19
+ A list of list where each sublist represents a row of the Airflows
20
+ table of the TRACE 700 Component Tree.
21
+ """
22
+ # set up things for unit conversion
23
+ flow_unit = 'L/s' if si_units else 'cfm'
24
+ flow_intensity_unit = 'L/s/sq m' if si_units else 'cfm/sq ft of wall'
25
+ flow, fi = VolumeFlowRate(), VolumeFlowRateIntensity()
26
+
27
+ # set up the names of the rows
28
+ row_names = [
29
+ 'Room Description',
30
+ 'Adjacent Air Transfer from Room',
31
+ 'Airflow Template',
32
+ 'Ventilation Method',
33
+ 'Ventilation Type',
34
+ 'Ventilation Cooling',
35
+ 'Ventilation Cooling Units',
36
+ 'Ventilation Heating',
37
+ 'Ventilation Heating Units',
38
+ 'People-based Rate (Rp)',
39
+ 'People-based Unit',
40
+ 'Area-based Rate (Ra)',
41
+ 'Area-based Unit',
42
+ 'Ventilation Schedule',
43
+ 'Std62.1-2004-2010 Clg Ez',
44
+ 'Std62.1-2004-2010 Clg Ez Pct',
45
+ 'Std62.1-2004-2010 Htg Ez',
46
+ 'Std62.1-2004-2010 Htg Ez Pct',
47
+ 'Std62.1-2004-2010 Er',
48
+ 'Std62.1-2004-2010 Er Pct',
49
+ 'DCV Min OA Intake',
50
+ 'DCV Min OA Intake Unit',
51
+ 'Infiltration Type',
52
+ 'Infiltration Cooling',
53
+ 'Infiltration Cooling Units',
54
+ 'Infiltration Heating',
55
+ 'Infiltration Heating Units',
56
+ 'Infiltration Schedule',
57
+ 'Main Supply Cooling',
58
+ 'Main Supply Cooling Units',
59
+ 'Main Supply Heating',
60
+ 'Main Supply Heating Units',
61
+ 'Aux Supply Cooling',
62
+ 'Aux Supply Cooling Units',
63
+ 'Aux Supply Heating',
64
+ 'Aux Supply Heating Units',
65
+ 'Cooling VAV Min Airflow',
66
+ 'Cooling VAV Min Airflow Units',
67
+ 'Heating VAV Max Airflow',
68
+ 'Heating VAV Max Airflow Units',
69
+ 'VAV Airflow Schedule',
70
+ 'VAV Type',
71
+ 'Room Exhaust',
72
+ 'Room Exhaust Units',
73
+ 'Room Exhaust Schedule'
74
+ ]
75
+
76
+ # loop through the rooms and add each of the attributes
77
+ airflow_mtx = []
78
+ for room in rooms:
79
+ # calculate the total outdoor air ventilation and infiltration
80
+ vent_obj = room.properties.energy.ventilation
81
+ vent_flow = vent_obj.room_absolute_flow(room) if vent_obj is not None else 0
82
+ inf_obj = room.properties.energy.infiltration
83
+ inf_flow = inf_obj.flow_per_exterior_area if inf_obj is not None else 0
84
+
85
+ # put all attributes into a list
86
+ airflow_attr = [
87
+ room.display_name,
88
+ '<<No adjacent room>>',
89
+ 'Default',
90
+ 'Sum of Outdoor Air',
91
+ 'None',
92
+ vent_flow,
93
+ flow_unit,
94
+ vent_flow,
95
+ flow_unit,
96
+ '',
97
+ '',
98
+ '',
99
+ '',
100
+ 'Available (100%)',
101
+ '',
102
+ '',
103
+ '',
104
+ '',
105
+ '',
106
+ '',
107
+ '',
108
+ '',
109
+ 'None',
110
+ inf_flow,
111
+ flow_intensity_unit,
112
+ inf_flow,
113
+ flow_intensity_unit,
114
+ 'Available (100%)',
115
+ '',
116
+ 'To be calculated',
117
+ '',
118
+ 'To be calculated',
119
+ '',
120
+ 'To be calculated',
121
+ '',
122
+ 'To be calculated',
123
+ '',
124
+ '% Clg Airflow',
125
+ '',
126
+ '% Clg Airflow',
127
+ 'Available (100%)',
128
+ 'Default',
129
+ '0',
130
+ 'air changes/hr',
131
+ 'Available (100%)'
132
+ ]
133
+ airflow_mtx.append(airflow_attr)
134
+
135
+ # transpose the matrix and convert SI units to IP
136
+ airflow_matrix = [list(row) for row in zip(*airflow_mtx)]
137
+ if not si_units:
138
+ airflow_matrix[5] = list(flow.to_unit(airflow_matrix[5], 'cfm', 'm3/s'))
139
+ airflow_matrix[7] = list(flow.to_unit(airflow_matrix[7], 'cfm', 'm3/s'))
140
+ airflow_matrix[23] = list(fi.to_unit(airflow_matrix[23], 'cfm/ft2', 'm3/s-m2'))
141
+ airflow_matrix[25] = list(fi.to_unit(airflow_matrix[25], 'cfm/ft2', 'm3/s-m2'))
142
+ else:
143
+ airflow_matrix[5] = list(flow.to_unit(airflow_matrix[5], 'L/s', 'm3/s'))
144
+ airflow_matrix[7] = list(flow.to_unit(airflow_matrix[7], 'L/s', 'm3/s'))
145
+ airflow_matrix[23] = list(fi.to_unit(airflow_matrix[23], 'L/s-m2', 'm3/s-m2'))
146
+ airflow_matrix[25] = list(fi.to_unit(airflow_matrix[25], 'L/s-m2', 'm3/s-m2'))
147
+
148
+ # round the numbers so that they display nicely
149
+ for row_i in (5, 7):
150
+ airflow_matrix[row_i] = [round(val, 1) for val in airflow_matrix[row_i]]
151
+ for row_i in (23, 25):
152
+ airflow_matrix[row_i] = [round(val, 3) for val in airflow_matrix[row_i]]
153
+
154
+ # insert the column for the row names
155
+ for row_name, row in zip(row_names, airflow_matrix):
156
+ row.insert(0, row_name)
157
+ return airflow_matrix
@@ -0,0 +1,18 @@
1
+ """dragonfly-trace commands which will be added to the dragonfly cli"""
2
+ import click
3
+ from dragonfly.cli import main
4
+
5
+ from .translate import translate
6
+
7
+
8
+ @click.group(help='dragonfly trace commands.')
9
+ @click.version_option()
10
+ def trace():
11
+ pass
12
+
13
+
14
+ # add sub-commands to trace
15
+ trace.add_command(translate)
16
+
17
+ # add trace sub-commands
18
+ main.add_command(trace)
@@ -0,0 +1,149 @@
1
+ """dragonfly trace translation commands."""
2
+ import click
3
+ import sys
4
+ import logging
5
+
6
+ from ladybug.commandutil import process_content_to_output
7
+ from dragonfly.model import Model
8
+ from dragonfly_trace.writer import model_to_trace700_csv as model_to_csv
9
+
10
+
11
+ _logger = logging.getLogger(__name__)
12
+
13
+
14
+ @click.group(help='Commands for translating URBANopt systems to OSM/IDF.')
15
+ def translate():
16
+ pass
17
+
18
+
19
+ @translate.command('model-to-trace700-csv')
20
+ @click.argument('model-file', type=click.Path(
21
+ exists=True, file_okay=True, dir_okay=False, resolve_path=True))
22
+ @click.option('--multiplier/--full-geometry', ' /-fg', help='Flag to note if the '
23
+ 'multipliers on each Building story will be passed along to the '
24
+ 'generated Honeybee Room objects or if full geometry objects should be '
25
+ 'written for each story in the building.', default=True, show_default=True)
26
+ @click.option('--plenum/--separate-plenum', '-p/-sp', help='Flag to indicate whether '
27
+ 'ceiling/floor plenum depths assigned to Room2Ds should simply be '
28
+ 'reported as plenum depths in the CSV or they should be used to generate '
29
+ 'distinct separated plenum rooms in the translation.',
30
+ default=True, show_default=True)
31
+ @click.option('--merge-method', '-m', help='Text to describe how the Room2Ds should '
32
+ 'be merged into individual Rooms during the translation. Specifying a '
33
+ 'value here can be an effective way to reduce the number of Room '
34
+ 'volumes in the resulting Model and, ultimately, yield a faster simulation '
35
+ 'time with less results to manage. Choose from: None, Zones, PlenumZones, '
36
+ 'Stories, PlenumStories.', type=str, default='None', show_default=True)
37
+ @click.option('--imperial/--metric', '-ip/-si', help='Flag to note whether imperial '
38
+ 'or metric units should be used for values in the output CSV.',
39
+ default=True, show_default=True)
40
+ @click.option('--geometry-ids/--geometry-names', ' /-gn', help='Flag to note whether a '
41
+ 'cleaned version of all geometry display names should be used instead '
42
+ 'of identifiers when translating the Model.',
43
+ default=True, show_default=True)
44
+ @click.option('--resource-ids/--resource-names', ' /-rn', help='Flag to note whether a '
45
+ 'cleaned version of all resource display names should be used instead '
46
+ 'of identifiers when translating the Model.',
47
+ default=True, show_default=True)
48
+ @click.option('--output-file', '-f', help='Optional CSV file to output the string '
49
+ 'of the translation. By default it printed out to stdout.',
50
+ type=click.File('w'), default='-', show_default=True)
51
+ def model_to_trace700_csv_cli(
52
+ model_file, multiplier, plenum, merge_method, imperial,
53
+ geometry_ids, resource_ids, output_file
54
+ ):
55
+ """Translate a Dragonfly Model to a CSV with tables for TRACE 700 attributes.
56
+
57
+ The resulting CSV tables can be copied into the tables that appear in the
58
+ Component Tree view of TRACE 700. The order and organization of rooms in
59
+ the resulting matrix should match that of the gbXML produced from the same model.
60
+
61
+ \b
62
+ Args:
63
+ model_file: Full path to a Dragonfly Model file (DFJSON or DFpkl).
64
+ """
65
+ try:
66
+ full_geometry = not multiplier
67
+ separate_plenum = not plenum
68
+ metric = not imperial
69
+ geo_names = not geometry_ids
70
+ res_names = not resource_ids
71
+ model_to_trace700_csv(
72
+ model_file, full_geometry, separate_plenum, merge_method,
73
+ metric, geo_names, res_names, output_file
74
+ )
75
+ except Exception as e:
76
+ _logger.exception('System translation failed.\n{}'.format(e))
77
+ sys.exit(1)
78
+ else:
79
+ sys.exit(0)
80
+
81
+
82
+ def model_to_trace700_csv(
83
+ model_file, full_geometry=False, separate_plenum=False, merge_method='None',
84
+ metric=False, geometry_names=False, resource_names=False, output_file=None,
85
+ multiplier=True, plenum=True, imperial=True, geometry_ids=True, resource_ids=True
86
+ ):
87
+ """Translate a Dragonfly Model to a CSV with tables for TRACE 700 attributes.
88
+
89
+ The resulting CSV tables can be copied into the tables that appear in the
90
+ Component Tree view of TRACE 700. The order and organization of rooms in
91
+ the resulting matrix should match that of the gbXML produced from the same model.
92
+
93
+ Args:
94
+ model: A dragonfly Model for which a TRACE 700 CSV matrix will be returned.
95
+ multiplier: If True, the multipliers on this Model's Stories will be
96
+ passed along to the CSV. If False, full geometry objects will be written
97
+ for each and every floor in the building that are represented through
98
+ multipliers and all resulting multipliers will be 1. (Default: True).
99
+ separate_plenum: Boolean to indicate whether ceiling/floor plenum depths
100
+ assigned to Room2Ds should simply be reported as plenum depths in the
101
+ CSV or they should be used to generate distinct separated plenum
102
+ rooms in the translation. (Default: False).
103
+ merge_method: An optional text string to describe how the Room2Ds should
104
+ be merged into individual Rooms during the translation. Specifying a
105
+ value here can be an effective way to reduce the number of Room
106
+ volumes in the resulting model and, ultimately, yield a faster
107
+ simulation time in the destination engine with fewer results
108
+ to manage. Note that Room2Ds will only be merged if they form a
109
+ continuous volume. Otherwise, there will be multiple Rooms per
110
+ zone or story, each with an integer added at the end of their
111
+ identifiers. Choose from the following options:
112
+
113
+ * None - No merging of Room2Ds will occur
114
+ * Zones - Room2Ds in the same zone will be merged
115
+ * PlenumZones - Only plenums in the same zone will be merged
116
+ * Stories - Rooms in the same story will be merged
117
+ * PlenumStories - Only plenums in the same story will be merged
118
+
119
+ metric: Boolean to note whether the units of the values in the resulting
120
+ matrix are in SI (True) instead of IP (False). (Default: False).
121
+ geometry_names: Boolean to note whether a cleaned version of all geometry
122
+ display names should be used instead of identifiers when translating
123
+ the Model to OSM and IDF. Using this flag will affect all Rooms, Faces,
124
+ Apertures, Doors, and Shades. It will generally result in more read-able
125
+ names in the OSM and IDF but this means that it will not be easy to map
126
+ the EnergyPlus results back to the original Honeybee Model. Cases
127
+ of duplicate IDs resulting from non-unique names will be resolved
128
+ by adding integers to the ends of the new IDs that are derived from
129
+ the name. (Default: False).
130
+ resource_names: Boolean to note whether a cleaned version of all resource
131
+ display names should be used instead of identifiers when translating
132
+ the Model to OSM and IDF. Using this flag will affect all Materials,
133
+ Constructions, ConstructionSets, Schedules, Loads, and ProgramTypes.
134
+ It will generally result in more read-able names for the resources
135
+ in the OSM and IDF. Cases of duplicate IDs resulting from non-unique
136
+ names will be resolved by adding integers to the ends of the new IDs
137
+ that are derived from the name. (Default: False).
138
+ output_file: Optional CSV file to output the CSV string of the translation.
139
+ By default this string will be returned from this method.
140
+ """
141
+ # load the model and translate it to a CSV
142
+ model = Model.from_file(model_file)
143
+ exclude_plenums = not separate_plenum
144
+ csv_str = model_to_csv(
145
+ model, multiplier, exclude_plenums, merge_method,
146
+ metric, geometry_names, resource_names
147
+ )
148
+
149
+ return process_content_to_output(csv_str, output_file)
@@ -0,0 +1,197 @@
1
+ # coding=utf-8
2
+ """Methods to write room loads to matrices for Trane TRACE tables."""
3
+ from __future__ import division
4
+
5
+ from ladybug.datatype.power import Power
6
+ from ladybug.datatype.energyflux import EnergyFlux
7
+ from honeybee.altnumber import autocalculate
8
+
9
+
10
+ def people_and_lights_trace700_matrix(rooms, si_units=False):
11
+ """Get a matrix for the "People & Lighting" table of the TRACE 700 Component Tree.
12
+
13
+ Args:
14
+ rooms: A list of dragonfly Room2Ds and honeybee Rooms for which the
15
+ TRACE 700 "People & Lighting" matrix will be returned.
16
+ si_units: Boolean to note whether the units of the values in the resulting
17
+ matrix are in SI (True) instead of IP (False). (Default: False).
18
+
19
+ Returns:
20
+ A list of list where each sublist represents a row of the People & Lighting
21
+ table of the TRACE 700 Component Tree.
22
+ """
23
+ # set up things for unit conversion
24
+ power_unit = 'kW' if si_units else 'Btu/h'
25
+ flux_unit = 'W/sq m' if si_units else 'W/sq ft'
26
+ power, flux = Power(), EnergyFlux()
27
+
28
+ # set up the names of the rows
29
+ row_names = [
30
+ 'Room Description',
31
+ 'Internal Loads Template',
32
+ 'People Activity',
33
+ 'People Schedule',
34
+ 'People Value',
35
+ 'People Value Units',
36
+ 'People Sensible ({})'.format(power_unit),
37
+ 'People Latent ({})'.format(power_unit),
38
+ 'Workstation Density',
39
+ 'Workstation Density Units',
40
+ 'Lighting Type',
41
+ 'ASHRAE Space/Area Type',
42
+ 'Lighting Value',
43
+ 'Lighting Value Units',
44
+ 'Lighting Schedule'
45
+ ]
46
+
47
+ # loop through the rooms and add each of the attributes
48
+ load_mtx = []
49
+ for room in rooms:
50
+ # calculate the total number of people
51
+ ppl_obj = room.properties.energy.people
52
+ if ppl_obj is not None:
53
+ ppl_count = room.floor_area * ppl_obj.people_per_area
54
+ act_sch = ppl_obj.activity_schedule
55
+ try: # ScheduleRuleset
56
+ vals = []
57
+ for sch in act_sch.typical_day_schedules:
58
+ vals.extend(sch.values)
59
+ act_level = max(vals)
60
+ except AttributeError: # ScheduleFixedInterval
61
+ act_level = max(act_sch.values)
62
+ latent_fract = ppl_obj.latent_fraction \
63
+ if ppl_obj.latent_fraction != autocalculate else 0.5
64
+ sensible_ppl = act_level * (1 - latent_fract)
65
+ latent_ppl = act_level * latent_fract
66
+ else:
67
+ ppl_count = 0
68
+ sensible_ppl = 73.26775
69
+ latent_ppl = 73.26775
70
+ # get the lighting power density
71
+ light_obj = room.properties.energy.lighting
72
+ if light_obj is not None:
73
+ lpd = light_obj.watts_per_area
74
+ light_type = r'LED Lighting 100% load to space'
75
+
76
+ # put all attributes into a list
77
+ load_attr = [
78
+ room.display_name,
79
+ 'Default',
80
+ 'None',
81
+ 'Cooling Only (Design)',
82
+ ppl_count,
83
+ 'People',
84
+ sensible_ppl,
85
+ latent_ppl,
86
+ 1,
87
+ 'workstation/person',
88
+ light_type,
89
+ '',
90
+ lpd,
91
+ flux_unit,
92
+ 'Cooling Only (Design)'
93
+ ]
94
+ load_mtx.append(load_attr)
95
+
96
+ # transpose the matrix and convert SI units to IP
97
+ load_matrix = [list(row) for row in zip(*load_mtx)]
98
+ if not si_units:
99
+ load_matrix[6] = list(power.to_unit(load_matrix[6], 'Btu/h', 'W'))
100
+ load_matrix[7] = list(power.to_unit(load_matrix[7], 'Btu/h', 'W'))
101
+ load_matrix[12] = list(flux.to_unit(load_matrix[12], 'W/ft2', 'W/m2'))
102
+ else:
103
+ load_matrix[6] = list(power.to_unit(load_matrix[6], 'kW', 'W'))
104
+ load_matrix[7] = list(power.to_unit(load_matrix[7], 'kW', 'W'))
105
+
106
+ # round the numbers so that they display nicely
107
+ for row_i in (6, 7):
108
+ load_matrix[row_i] = [round(val) for val in load_matrix[row_i]]
109
+ for row_i in (4, 12):
110
+ load_matrix[row_i] = [round(val, 3) for val in load_matrix[row_i]]
111
+
112
+ # insert the column for the row names
113
+ for row_name, row in zip(row_names, load_matrix):
114
+ row.insert(0, row_name)
115
+ return load_matrix
116
+
117
+
118
+ def miscellaneous_loads_trace700_matrix(rooms, si_units=False):
119
+ """Get a matrix for the "People & Lighting" table of the TRACE 700 Component Tree.
120
+
121
+ Args:
122
+ rooms: A list of dragonfly Room2Ds and honeybee Rooms for which the
123
+ TRACE 700 "People & Lighting" matrix will be returned.
124
+ si_units: Boolean to note whether the units of the values in the resulting
125
+ matrix are in SI (True) instead of IP (False). (Default: False).
126
+
127
+ Returns:
128
+ A list of list where each sublist represents a row of the People & Lighting
129
+ table of the TRACE 700 Component Tree.
130
+ """
131
+ # set up things for unit conversion
132
+ power_unit = 'W'
133
+ flux_unit = 'W/sq m' if si_units else 'W/sq ft'
134
+ flux = EnergyFlux()
135
+
136
+ # set up the names of the rows
137
+ row_names = [
138
+ 'Misc Load Description',
139
+ 'Room Description',
140
+ 'Type',
141
+ 'Schedule',
142
+ 'Value',
143
+ 'Units',
144
+ 'Energy Meter',
145
+ 'Data Center Equipment'
146
+ ]
147
+
148
+ # loop through the rooms and add each of the attributes
149
+ load_mtx = []
150
+ for room in rooms:
151
+ # calculate the total density of equipment
152
+ epd, e_type = 0, 'None'
153
+ ele_obj = room.properties.energy.electric_equipment
154
+ if ele_obj is not None:
155
+ epd += (ele_obj.watts_per_area * (1 - ele_obj.lost_fraction))
156
+ e_type = 'Electricity'
157
+ gas_obj = room.properties.energy.gas_equipment
158
+ if gas_obj is not None:
159
+ epd += (gas_obj.watts_per_area * (1 - gas_obj.lost_fraction))
160
+ e_type = 'Gas'
161
+
162
+ # if there are process loads assigned, specify load in absolute Watts
163
+ process_load = sum(load.watts * (1 - load.lost_fraction)
164
+ for load in room.properties.energy.process_loads)
165
+ if process_load != 0:
166
+ load_value = process_load + (epd * room.floor_area)
167
+ load_unit = power_unit
168
+ else:
169
+ load_value = epd
170
+ load_unit = flux_unit
171
+
172
+ # put all attributes into a list
173
+ load_attr = [
174
+ '{} Misc Load'.format(room.display_name),
175
+ room.display_name,
176
+ 'None',
177
+ 'Cooling Only (Design)',
178
+ load_value,
179
+ load_unit,
180
+ e_type,
181
+ 'No'
182
+ ]
183
+ load_mtx.append(load_attr)
184
+
185
+ # transpose the matrix and convert SI units to IP
186
+ load_matrix = [list(row) for row in zip(*load_mtx)]
187
+ if load_unit == flux_unit:
188
+ if not si_units:
189
+ load_matrix[4] = list(flux.to_unit(load_matrix[4], 'W/ft2', 'W/m2'))
190
+ load_matrix[4] = [round(val, 2) for val in load_matrix[4]]
191
+ else:
192
+ load_matrix[4] = [round(val) for val in load_matrix[4]]
193
+
194
+ # insert the column for the row names
195
+ for row_name, row in zip(row_names, load_matrix):
196
+ row.insert(0, row_name)
197
+ return load_matrix