Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor parametric schedules #1718

Merged
merged 25 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
88569a1
add schedule_day_populate_from_array_of_vals and schedule_ruleset_cre…
eringold Mar 14, 2024
f9a4b57
refactor spaces_get_occupancy_schedules
eringold Mar 14, 2024
de92842
minor updates to test_spaces_get_occupancy_schedule
eringold Mar 14, 2024
464cab2
create schedule rules to match hours of operation and always be modified
eringold Mar 19, 2024
06ca562
new methods to get schedule day/rule info
eringold Mar 19, 2024
0d3e580
clean up create_rules_from_day_list
eringold Mar 19, 2024
52c16d4
update gather_inputs_parametric_schedules test - now passing
eringold Mar 19, 2024
7c14284
adds method to adjust thermostats to follow user input hours of opera…
eringold Apr 2, 2024
72fbe20
add test for thermostat adjustment in simple comstock workflow
eringold Apr 2, 2024
546a042
Merge branch 'master' of https://github.com/NREL/openstudio-standards…
eringold Apr 2, 2024
48cd9bb
lil doc typo
eringold Apr 2, 2024
af08812
remove author tag
eringold Apr 2, 2024
3d7ff07
Merge branch 'master' into parametric_refactor2
mdahlhausen Apr 4, 2024
e28716b
rubocop edits
mdahlhausen Apr 4, 2024
19a6aea
formatting edits
mdahlhausen Apr 4, 2024
b9402e1
remove save navigation operator
eringold Apr 4, 2024
17d9f28
test_schedule_ruleset_get_annual_days_used
eringold Apr 4, 2024
8aefff1
test_schedule_ruleset_get_schedule_day_rule_indices
eringold Apr 4, 2024
796868b
test_schedule_day_populate_from_array_of_values
eringold Apr 5, 2024
9a0ebdb
schedule_day_populate_values_from_array_of_values enforce value_array…
eringold Apr 5, 2024
ff80d96
test_schedule_ruleset_create_rules_from_day_list
eringold Apr 5, 2024
b4feb93
reorder assert_equal statements
eringold Apr 5, 2024
2a9e9ff
add parameter descriptions
eringold Apr 5, 2024
a2184de
parametric schedule method name changes
mdahlhausen Apr 5, 2024
91827c9
Merge branch 'master' into parametric_refactor2
mdahlhausen Apr 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 13 additions & 16 deletions lib/openstudio-standards/create_typical/create_typical.rb
Original file line number Diff line number Diff line change
Expand Up @@ -630,9 +630,9 @@ def self.create_typical_building_from_model(model,
'hydronic'
end

# Group the zones by occupancy type. Only split out non-dominant groups if their total area exceeds the limit.
min_area_m2 = OpenStudio.convert(20_000, 'ft^2', 'm^2').get
sys_groups = OpenstudioStandards::Geometry.model_group_thermal_zones_by_occupancy_type(model, min_area_m2: min_area_m2)
# Group the zones by occupancy type. Only split out non-dominant groups if their total area exceeds the limit.
min_area_m2 = OpenStudio.convert(20_000, 'ft^2', 'm^2').get
sys_groups = OpenstudioStandards::Geometry.model_group_thermal_zones_by_occupancy_type(model, min_area_m2: min_area_m2)

# For each group, infer the HVAC system type.
sys_groups.each do |sys_group|
Expand All @@ -656,8 +656,8 @@ def self.create_typical_building_from_model(model,
sys_type # same as primary system type
end

# group zones
story_zone_lists = OpenstudioStandards::Geometry.model_group_thermal_zones_by_building_story(model, sys_group['zones'])
# group zones
story_zone_lists = OpenstudioStandards::Geometry.model_group_thermal_zones_by_building_story(model, sys_group['zones'])

# On each story, add the primary system to the primary zones
# and add the secondary system to any zones that are different.
Expand Down Expand Up @@ -696,14 +696,14 @@ def self.create_typical_building_from_model(model,
end
end

else
# HVAC system_type specified
# Group the zones by occupancy type. Only split out non-dominant groups if their total area exceeds the limit.
min_area_m2 = OpenStudio.convert(20_000, 'ft^2', 'm^2').get
sys_groups = OpenstudioStandards::Geometry.model_group_thermal_zones_by_occupancy_type(model, min_area_m2: min_area_m2)
sys_groups.each do |sys_group|
# group zones
story_zone_groups = OpenstudioStandards::Geometry.model_group_thermal_zones_by_building_story(model, sys_group['zones'])
else
# HVAC system_type specified
# Group the zones by occupancy type. Only split out non-dominant groups if their total area exceeds the limit.
min_area_m2 = OpenStudio.convert(20_000, 'ft^2', 'm^2').get
sys_groups = OpenstudioStandards::Geometry.model_group_thermal_zones_by_occupancy_type(model, min_area_m2: min_area_m2)
sys_groups.each do |sys_group|
# group zones
story_zone_groups = OpenstudioStandards::Geometry.model_group_thermal_zones_by_building_story(model, sys_group['zones'])

# Add the user specified HVAC system for each story.
# Single-zone systems will get one per zone.
Expand All @@ -714,9 +714,7 @@ def self.create_typical_building_from_model(model,
end
end
end

end

else
# If user specified a mapping of HVAC systems to zones
user_hvac_mapping['systems'].each do |system_hash|
Expand All @@ -736,7 +734,6 @@ def self.create_typical_building_from_model(model,
end
end
end

end

# hours of operation
Expand Down
28 changes: 28 additions & 0 deletions lib/openstudio-standards/schedules/information.rb
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,34 @@ def self.schedule_ruleset_get_day_schedules(schedule_ruleset, include_design_day
return profiles
end

# Return the annual days of year that covered by each rule of a schedule ruleset
#
# @param schedule_ruleset [OpenStudio::Model::ScheduleRuleset] OpenStudio ScheduleRuleset object
# @return [Hash] hash of rule_index => [days_used]. Default day has rule_index = -1
def self.schedule_ruleset_get_annual_days_used(schedule_ruleset)
year_description = schedule_ruleset.model.getYearDescription
year = year_description.assumedYear
year_start_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new('January'), 1, year)
year_end_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new('December'), 31, year)
sch_indices_vector = schedule_ruleset.getActiveRuleIndices(year_start_date, year_end_date)
days_used_hash = Hash.new { |h, k| h[k] = [] }
sch_indices_vector.uniq.sort.each do |rule_i|
sch_indices_vector.each_with_index { |rule, i| days_used_hash[rule_i] << i + 1 if rule_i == rule }
end
return days_used_hash
end

# Returns the rule indices associated with defaultDay and Rule days for a given ScheduleRuleset
#
# @param schedule_ruleset [OpenStudio::Model::ScheduleRuleset] OpenStudio ScheduleRuleset object
# @return [Hash] hash of ScheduleDay => rule index. Default day has rule index of -1
def self.schedule_ruleset_get_schedule_day_rule_indices(schedule_ruleset)
schedule_day_hash = {}
schedule_day_hash[schedule_ruleset.defaultDaySchedule] = -1
schedule_ruleset.scheduleRules.each { |rule| schedule_day_hash[rule.daySchedule] = rule.ruleIndex }
return schedule_day_hash
end

# @!endgroup Information:ScheduleRuleset
end
end
62 changes: 62 additions & 0 deletions lib/openstudio-standards/schedules/modify.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,28 @@ def self.schedule_day_set_hours_of_operation(schedule_day, start_time, end_time)
schedule_day.addValue(twenty_four_hours, 1) # 1 from start of today's hours until midnight
end
end

# Sets the values of a day schedule from an array of values
# Clears out existing time value pairs and sets to supplied values
#
# @param schedule_day [OpenStudio::Model::ScheduleDay] The day schedule to set.
# @param value_array [Array] Array of 24 values. Schedule times set based on value index. Identical values will be skipped.
# @return [OpenStudio::Model::ScheduleDay]
def self.schedule_day_populate_from_array_of_values(schedule_day, value_array)
schedule_day.clearValues
if value_array.size != 24
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Schedules.Modify', "#{__method__} expects value_array to contain 24 values, instead #{value_array.size} values were given. Resulting schedule will use first #{[24, value_array.size].min} values")
end

value_array[0..23].each_with_index do |value, h|
next if value == value_array[h + 1]

time = OpenStudio::Time.new(0, h + 1, 0, 0)
schedule_day.addValue(time, value)
end
return schedule_day
end

# @!endgroup Modify:ScheduleDay

# @!group Modify:ScheduleRuleset
Expand Down Expand Up @@ -673,6 +695,46 @@ def self.schedule_ruleset_cleanup_profiles(schedule_ruleset)
return schedule_ruleset
end

# creates a minimal set of ScheduleRules that applies to all days in a given array of day of year indices
#
# @param schedule_ruleset [OpenStudio::Model::ScheduleRuleset]
# @param days_used [Array] array of day of year integers
# @param schedule_day [OpenStudio::Model::ScheduleDay] optional day schedule to apply to new rule. A new default schedule will be created for each rule if nil
# @return [Array]
def self.schedule_ruleset_create_rules_from_day_list(schedule_ruleset, days_used, schedule_day: nil)
# get year from schedule_ruleset
year = schedule_ruleset.model.getYearDescription.assumedYear

# split day_used into sub arrays of consecutive days
consec_days = days_used.chunk_while { |i, j| i + 1 == j }.to_a

# split consec_days into sub arrays of consecutive weeks by checking that any value in next array differs by seven from a value in this array
consec_weeks = consec_days.chunk_while { |i, j| i.product(j).any? { |x, y| (x - y).abs == 7 } }.to_a

# make new rule for blocks of consectutive weeks
rules = []
consec_weeks.each do |week_group|
if schedule_day.nil?
OpenStudio.logFree(OpenStudio::Debug, 'openstudio.standards.Parametric.ScheduleRuleset', 'Creating new Rule Schedule from days_used vector with new Day Schedule')
rule = OpenStudio::Model::ScheduleRule.new(schedule_ruleset)
else
OpenStudio.logFree(OpenStudio::Debug, 'openstudio.standards.Parametric.ScheduleRuleset', "Creating new Rule Schedule from days_used vector with clone of Day Schedule: #{schedule_day.name.get}")
rule = OpenStudio::Model::ScheduleRule.new(schedule_ruleset, schedule_day)
end

# set day types and dates
dates = week_group.flatten.map { |d| OpenStudio::Date.fromDayOfYear(d, year) }
day_types = dates.map { |date| date.dayOfWeek.valueName }.uniq
day_types.each { |type| rule.send("setApply#{type}", true) }
rule.setStartDate(dates.min)
rule.setEndDate(dates.max)

rules << rule
end

return rules
end

# @!endgroup Modify:ScheduleRuleset
end
end
Loading