honeybee-openstudio 2.10.4 → 2.11.0
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/honeybee-openstudio.gemspec +1 -1
- data/lib/measures/from_honeybee_model/measure.rb +23 -0
- data/lib/to_openstudio/model.rb +64 -4
- data/lib/to_openstudio/schedule/fixed_interval.rb +146 -30
- data/lib/to_openstudio/schedule/ruleset.rb +2 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f86f836af76719222d4ce8393755cd79a6243e52e700c40f54808f72b6d9f2bf
|
4
|
+
data.tar.gz: 98176f5bb8055c871951f56b21717f9f6b3efc35e2b87ae5dbf98520cb2eb954
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d2ddb1e445513e442caf0e7ec9846ce9653a25291cead36e00d7b2ca41e3f8b928d5c5a8ffa79880c11d557293c2af22e211b7be525eef32db3ee315ce15209
|
7
|
+
data.tar.gz: 3f69624f318a6d3dc5dc8db9ddafd850dbe487bf9d135996cfa9e1cd91fb286cbb1f49e63fb825f6e19dba79bda98ee396a604e4c8fe2027e2e0249e91a323a9
|
data/.gitignore
CHANGED
data/honeybee-openstudio.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'honeybee-openstudio'
|
7
|
-
spec.version = '2.
|
7
|
+
spec.version = '2.11.0'
|
8
8
|
spec.authors = ['Tanushree Charan', 'Dan Macumber', 'Chris Mackey', 'Mostapha Sadeghipour Roudsari']
|
9
9
|
spec.email = ['tanushree.charan@nrel.gov', 'chris@ladybug.tools']
|
10
10
|
|
@@ -60,6 +60,19 @@ class FromHoneybeeModel < OpenStudio::Measure::ModelMeasure
|
|
60
60
|
model_json.setDisplayName('Path to the Honeybee Model JSON file')
|
61
61
|
args << model_json
|
62
62
|
|
63
|
+
# Make an argument for schedule csv dir
|
64
|
+
schedule_csv_dir = OpenStudio::Measure::OSArgument.makeStringArgument('schedule_csv_dir', false)
|
65
|
+
schedule_csv_dir.setDisplayName('Directory for exported CSV Schedules')
|
66
|
+
schedule_csv_dir.setDescription('If set, Fixed Interval Schedules will be translated to CSV Schedules in this directory')
|
67
|
+
schedule_csv_dir.setDefaultValue('')
|
68
|
+
args << schedule_csv_dir
|
69
|
+
|
70
|
+
# Make an argument for include datetimes
|
71
|
+
include_datetimes = OpenStudio::Measure::OSArgument.makeBoolArgument('include_datetimes', false)
|
72
|
+
include_datetimes.setDisplayName('Include date time column in exported CSV Schedules')
|
73
|
+
include_datetimes.setDefaultValue(false)
|
74
|
+
args << include_datetimes
|
75
|
+
|
63
76
|
return args
|
64
77
|
end
|
65
78
|
|
@@ -72,6 +85,8 @@ class FromHoneybeeModel < OpenStudio::Measure::ModelMeasure
|
|
72
85
|
end
|
73
86
|
|
74
87
|
model_json = runner.getStringArgumentValue('model_json', user_arguments)
|
88
|
+
schedule_csv_dir = runner.getStringArgumentValue('schedule_csv_dir', user_arguments)
|
89
|
+
include_datetimes = runner.getBoolArgumentValue('include_datetimes', user_arguments)
|
75
90
|
|
76
91
|
if !File.exist?(model_json)
|
77
92
|
runner.registerError("Cannot find file '#{model_json}'")
|
@@ -80,6 +95,14 @@ class FromHoneybeeModel < OpenStudio::Measure::ModelMeasure
|
|
80
95
|
|
81
96
|
honeybee_model = Honeybee::Model.read_from_disk(model_json)
|
82
97
|
|
98
|
+
if schedule_csv_dir && !schedule_csv_dir.empty?
|
99
|
+
if !Dir.exist?(schedule_csv_dir)
|
100
|
+
runner.registerError("Directory for exported CSV Schedules does not exist '#{schedule_csv_dir}'")
|
101
|
+
return false
|
102
|
+
end
|
103
|
+
honeybee_model.set_schedule_csv_dir(schedule_csv_dir, include_datetimes)
|
104
|
+
end
|
105
|
+
|
83
106
|
STDOUT.flush
|
84
107
|
honeybee_model.to_openstudio_model(model)
|
85
108
|
STDOUT.flush
|
data/lib/to_openstudio/model.rb
CHANGED
@@ -34,9 +34,38 @@ require 'honeybee/model'
|
|
34
34
|
require 'openstudio'
|
35
35
|
|
36
36
|
module Honeybee
|
37
|
+
|
38
|
+
def self.write_schedule_csv(schedule_csv_dir, schedule_csv)
|
39
|
+
filename = schedule_csv[:filename]
|
40
|
+
columns = schedule_csv[:columns]
|
41
|
+
if !columns.empty?
|
42
|
+
n = columns[0].size
|
43
|
+
path = File.join(schedule_csv_dir, filename)
|
44
|
+
File.open(path, 'w') do |file|
|
45
|
+
(0...n).each do |i|
|
46
|
+
row = []
|
47
|
+
columns.each do |column|
|
48
|
+
row << column[i]
|
49
|
+
end
|
50
|
+
file.puts row.join(',')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
37
56
|
class Model
|
38
57
|
|
39
58
|
attr_reader :openstudio_model
|
59
|
+
attr_reader :schedule_csv_dir, :include_datetimes, :schedule_csvs
|
60
|
+
|
61
|
+
# if a schedule csv dir is specified then ScheduleFixedIntervalAbridged objects
|
62
|
+
# will be translated to ScheduleFile objects instead of ScheduleFixedInterval
|
63
|
+
# the optional schedule_csv_include_datetimes argument controls whether schedule csv
|
64
|
+
# files include a first column of date times for verification
|
65
|
+
def set_schedule_csv_dir(schedule_csv_dir, include_datetimes = false)
|
66
|
+
@schedule_csv_dir = schedule_csv_dir
|
67
|
+
@include_datetimes = include_datetimes
|
68
|
+
end
|
40
69
|
|
41
70
|
# convert to openstudio model, clears errors and warnings
|
42
71
|
def to_openstudio_model(openstudio_model=nil, log_report=true)
|
@@ -99,7 +128,7 @@ module Honeybee
|
|
99
128
|
create_schedule_type_limits(@hash[:properties][:energy][:schedule_type_limits])
|
100
129
|
end
|
101
130
|
if @hash[:properties][:energy][:schedules]
|
102
|
-
create_schedules(@hash[:properties][:energy][:schedules])
|
131
|
+
create_schedules(@hash[:properties][:energy][:schedules], false, true)
|
103
132
|
end
|
104
133
|
|
105
134
|
if log_report
|
@@ -283,7 +312,32 @@ module Honeybee
|
|
283
312
|
end
|
284
313
|
end
|
285
314
|
|
286
|
-
def create_schedules(schedule_dicts, check_existing=false)
|
315
|
+
def create_schedules(schedule_dicts, check_existing=false, check_leap_year=true)
|
316
|
+
|
317
|
+
# clear out schedule_csvs
|
318
|
+
@schedule_csvs = {}
|
319
|
+
|
320
|
+
if check_leap_year
|
321
|
+
is_leap_year = :unknown
|
322
|
+
schedule_dicts.each do |schedule|
|
323
|
+
# set is leap year = true in case start date has 3 integers
|
324
|
+
this_leap_year = false
|
325
|
+
if schedule[:start_date] && schedule[:start_date][2]
|
326
|
+
this_leap_year = true
|
327
|
+
end
|
328
|
+
if is_leap_year == :unknown
|
329
|
+
is_leap_year = this_leap_year
|
330
|
+
elsif is_leap_year != this_leap_year
|
331
|
+
raise("Mixed leap year information.")
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
if is_leap_year != :unknown
|
336
|
+
year_description = openstudio_model.getYearDescription
|
337
|
+
year_description.setIsLeapYear(is_leap_year)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
287
341
|
schedule_dicts.each do |schedule|
|
288
342
|
# check if there's already a schedule in the model with the identifier
|
289
343
|
add_obj = true
|
@@ -305,9 +359,15 @@ module Honeybee
|
|
305
359
|
else
|
306
360
|
raise("Unknown schedule type #{schedule_type}.")
|
307
361
|
end
|
308
|
-
schedule_object.to_openstudio(@openstudio_model)
|
362
|
+
schedule_object.to_openstudio(@openstudio_model, @schedule_csv_dir, @include_datetimes, @schedule_csvs)
|
309
363
|
end
|
310
364
|
end
|
365
|
+
|
366
|
+
# write schedule csvs
|
367
|
+
@schedule_csvs.each_value do |schedule_csv|
|
368
|
+
Honeybee.write_schedule_csv(@schedule_csv_dir, schedule_csv)
|
369
|
+
end
|
370
|
+
|
311
371
|
end
|
312
372
|
|
313
373
|
def create_program_types(program_dicts, check_existing=false)
|
@@ -343,7 +403,7 @@ module Honeybee
|
|
343
403
|
end
|
344
404
|
@@standards[:schedules].each do |schedule|
|
345
405
|
if schedule[:identifier] == 'Always On'
|
346
|
-
create_schedules([schedule], true)
|
406
|
+
create_schedules([schedule], true, false)
|
347
407
|
end
|
348
408
|
end
|
349
409
|
|
@@ -42,26 +42,60 @@ module Honeybee
|
|
42
42
|
nil
|
43
43
|
end
|
44
44
|
|
45
|
-
def to_openstudio(openstudio_model)
|
45
|
+
def to_openstudio(openstudio_model, schedule_csv_dir = nil, include_datetimes = nil, schedule_csvs = nil)
|
46
|
+
if schedule_csv_dir
|
47
|
+
to_schedule_file(openstudio_model, schedule_csv_dir, include_datetimes, schedule_csvs)
|
48
|
+
else
|
49
|
+
to_schedule_fixed_interval(openstudio_model)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def start_month
|
54
|
+
if @hash[:start_date]
|
55
|
+
return @hash[:start_date][0]
|
56
|
+
end
|
57
|
+
defaults[:start_date][:default][0]
|
58
|
+
end
|
59
|
+
|
60
|
+
def start_day
|
61
|
+
if @hash[:start_date]
|
62
|
+
return @hash[:start_date][1]
|
63
|
+
end
|
64
|
+
defaults[:start_date][:default][1]
|
65
|
+
end
|
66
|
+
|
67
|
+
def interpolate
|
68
|
+
if @hash[:interpolate]
|
69
|
+
return @hash[:interpolate]
|
70
|
+
end
|
71
|
+
defaults[:interpolate][:default]
|
72
|
+
end
|
73
|
+
|
74
|
+
def timestep
|
75
|
+
if @hash[:timestep]
|
76
|
+
return @hash[:timestep]
|
77
|
+
end
|
78
|
+
defaults[:timestep][:default]
|
79
|
+
end
|
80
|
+
|
81
|
+
def placeholder_value
|
82
|
+
if @hash[:placeholder_value]
|
83
|
+
return @hash[:placeholder_value]
|
84
|
+
end
|
85
|
+
defaults[:placeholder_value][:default]
|
86
|
+
end
|
87
|
+
|
88
|
+
def to_schedule_fixed_interval(openstudio_model)
|
46
89
|
# create the new schedule
|
47
90
|
os_fi_schedule = OpenStudio::Model::ScheduleFixedInterval.new(openstudio_model)
|
48
91
|
os_fi_schedule.setName(@hash[:identifier])
|
49
92
|
|
50
93
|
# assign start date
|
51
|
-
|
52
|
-
|
53
|
-
os_fi_schedule.setStartDay(@hash[:start_date][1])
|
54
|
-
else
|
55
|
-
os_fi_schedule.setStartMonth(defaults[:start_date][:default][0])
|
56
|
-
os_fi_schedule.setStartDay(defaults[:start_date][:default][1])
|
57
|
-
end
|
94
|
+
os_fi_schedule.setStartMonth(start_month)
|
95
|
+
os_fi_schedule.setStartDay(start_day)
|
58
96
|
|
59
97
|
# assign the interpolate value
|
60
|
-
|
61
|
-
os_fi_schedule.setInterpolatetoTimestep(@hash[:interpolate])
|
62
|
-
else
|
63
|
-
os_fi_schedule.setInterpolatetoTimestep(defaults[:interpolate][:default])
|
64
|
-
end
|
98
|
+
os_fi_schedule.setInterpolatetoTimestep(interpolate)
|
65
99
|
|
66
100
|
# assign the schedule type limit
|
67
101
|
if @hash[:schedule_type_limit]
|
@@ -73,32 +107,114 @@ module Honeybee
|
|
73
107
|
end
|
74
108
|
|
75
109
|
# assign the timestep
|
76
|
-
|
77
|
-
|
78
|
-
interval_length = 60 / timestep
|
79
|
-
os_fi_schedule.setIntervalLength(interval_length)
|
80
|
-
else
|
81
|
-
timestep = defaults[:timestep][:default]
|
82
|
-
interval_length = 60 / timestep
|
83
|
-
os_fi_schedule.setIntervalLength(interval_length)
|
84
|
-
end
|
110
|
+
interval_length = 60 / timestep
|
111
|
+
os_fi_schedule.setIntervalLength(interval_length)
|
85
112
|
openstudio_interval_length = OpenStudio::Time.new(0, 0, interval_length)
|
86
113
|
|
87
114
|
# assign the values as a timeseries
|
88
115
|
year_description = openstudio_model.getYearDescription
|
116
|
+
start_date = year_description.makeDate(start_month, start_day)
|
117
|
+
timeseries = OpenStudio::TimeSeries.new(start_date, openstudio_interval_length, OpenStudio.createVector(@hash[:values]), '')
|
118
|
+
os_fi_schedule.setTimeSeries(timeseries)
|
89
119
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
120
|
+
os_fi_schedule
|
121
|
+
end
|
122
|
+
|
123
|
+
def to_schedule_file(openstudio_model, schedule_csv_dir, include_datetimes, schedule_csvs)
|
124
|
+
|
125
|
+
# in order to combine schedules in the same csv file they must have the same key
|
126
|
+
schedule_key = "#{@hash[:identifier]}_#{start_month}_#{start_day}_#{timestep}"
|
94
127
|
|
95
|
-
|
128
|
+
# get start and end date times
|
129
|
+
yd = openstudio_model.getYearDescription
|
130
|
+
date_time = OpenStudio::DateTime.new(yd.makeDate(1, 1), OpenStudio::Time.new(0,0,0))
|
131
|
+
start_date_time = OpenStudio::DateTime.new(yd.makeDate(start_month, start_day), OpenStudio::Time.new(0,0,0))
|
132
|
+
end_date_time = OpenStudio::DateTime.new(yd.makeDate(12, 31), OpenStudio::Time.new(1,0,0))
|
96
133
|
|
134
|
+
# get timestep
|
135
|
+
interval_length = 60 / timestep
|
136
|
+
dt = OpenStudio::Time.new(0, 0, interval_length, 0)
|
137
|
+
|
138
|
+
# get values and date times
|
97
139
|
values = @hash[:values]
|
98
|
-
|
99
|
-
|
140
|
+
num_values = values.size
|
141
|
+
i_values = 0
|
142
|
+
padded_values = []
|
143
|
+
date_times = []
|
144
|
+
pv = placeholder_value
|
100
145
|
|
101
|
-
|
146
|
+
while date_time < end_date_time
|
147
|
+
date = date_time.date
|
148
|
+
time = date_time.time
|
149
|
+
date_times << "#{date.dayOfMonth} #{date.monthOfYear.valueName} #{time.hours.to_s.rjust(2,'0')}:#{time.minutes.to_s.rjust(2,'0')}"
|
150
|
+
|
151
|
+
if date_time < start_date_time
|
152
|
+
padded_values << pv
|
153
|
+
elsif i_values < num_values
|
154
|
+
padded_values << values[i_values]
|
155
|
+
i_values += 1
|
156
|
+
else
|
157
|
+
padded_values << pv
|
158
|
+
end
|
159
|
+
|
160
|
+
date_time += dt
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
# find or create the schedule csv object which will hold the filename and columns
|
165
|
+
filename = nil
|
166
|
+
columns = nil
|
167
|
+
os_external_file = nil
|
168
|
+
schedule_csv = schedule_csvs[schedule_key]
|
169
|
+
if schedule_csv.nil?
|
170
|
+
# file name to write
|
171
|
+
filename = "#{@hash[:identifier]}.csv".gsub(' ', '_')
|
172
|
+
|
173
|
+
# columns of data
|
174
|
+
columns = []
|
175
|
+
if include_datetimes
|
176
|
+
columns << ['Date Times'].concat(date_times)
|
177
|
+
end
|
178
|
+
|
179
|
+
# schedule csv file must exist even though it has no content yet
|
180
|
+
path = File.join(schedule_csv_dir, filename)
|
181
|
+
if !File.exist?(path)
|
182
|
+
File.open(path, 'w') {|f| f.puts ''}
|
183
|
+
end
|
184
|
+
|
185
|
+
# get the external file which points to the schedule csv file
|
186
|
+
os_external_file = OpenStudio::Model::ExternalFile.getExternalFile(openstudio_model, filename)
|
187
|
+
os_external_file = os_external_file.get
|
188
|
+
|
189
|
+
schedule_csv = {filename: filename, columns: columns, os_external_file: os_external_file}
|
190
|
+
schedule_csvs[schedule_key] = schedule_csv
|
191
|
+
else
|
192
|
+
filename = schedule_csv[:filename]
|
193
|
+
columns = schedule_csv[:columns]
|
194
|
+
os_external_file = schedule_csv[:os_external_file]
|
195
|
+
end
|
196
|
+
|
197
|
+
# insert the padded_values to write later
|
198
|
+
columns << [@hash[:identifier]].concat(padded_values)
|
199
|
+
|
200
|
+
# create the schedule file
|
201
|
+
column = columns.size # 1 based index
|
202
|
+
rowsToSkip = 1
|
203
|
+
os_schedule_file = OpenStudio::Model::ScheduleFile.new(os_external_file, column, rowsToSkip)
|
204
|
+
os_schedule_file.setName(@hash[:identifier])
|
205
|
+
os_schedule_file.setInterpolatetoTimestep(interpolate)
|
206
|
+
os_schedule_file.setMinutesperItem(interval_length.to_s)
|
207
|
+
|
208
|
+
# assign the schedule type limit
|
209
|
+
if @hash[:schedule_type_limit]
|
210
|
+
schedule_type_limit = openstudio_model.getScheduleTypeLimitsByName(@hash[:schedule_type_limit])
|
211
|
+
unless schedule_type_limit.empty?
|
212
|
+
schedule_type_limit_object = schedule_type_limit.get
|
213
|
+
os_schedule_file.setScheduleTypeLimits(schedule_type_limit_object)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
os_schedule_file
|
102
218
|
end
|
103
219
|
|
104
220
|
end #ScheduleFixedIntervalAbridged
|
@@ -42,7 +42,8 @@ module Honeybee
|
|
42
42
|
nil
|
43
43
|
end
|
44
44
|
|
45
|
-
def to_openstudio(openstudio_model)
|
45
|
+
def to_openstudio(openstudio_model, schedule_csv_dir = nil, include_datetimes = nil, schedule_csvs = nil)
|
46
|
+
|
46
47
|
# create openstudio schedule ruleset object
|
47
48
|
os_sch_ruleset = OpenStudio::Model::ScheduleRuleset.new(openstudio_model)
|
48
49
|
os_sch_ruleset.setName(@hash[:identifier])
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: honeybee-openstudio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tanushree Charan
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: exe
|
13
13
|
cert_chain: []
|
14
|
-
date: 2021-01-
|
14
|
+
date: 2021-01-06 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|