openstudio-calibration 0.3.1 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +3 -1
- data/CHANGELOG.md +18 -0
- data/Gemfile +6 -0
- data/Jenkinsfile +4 -3
- data/LICENSE.md +1 -1
- data/README.md +13 -2
- data/Rakefile +1 -1
- data/doc_templates/LICENSE.md +1 -1
- data/doc_templates/copyright_erb.txt +1 -1
- data/doc_templates/copyright_js.txt +1 -1
- data/doc_templates/copyright_ruby.txt +1 -1
- data/lib/measures/AddMonthlyJSONUtilityData/LICENSE.md +1 -1
- data/lib/measures/AddMonthlyJSONUtilityData/measure.rb +1 -1
- data/lib/measures/AddMonthlyJSONUtilityData/measure.xml +12 -11
- data/lib/measures/AddMonthlyUtilityData/LICENSE.md +1 -1
- data/lib/measures/AddMonthlyUtilityData/measure.rb +1 -1
- data/lib/measures/AddMonthlyUtilityData/measure.xml +13 -12
- data/lib/measures/CalibrationReports/LICENSE.md +1 -1
- data/lib/measures/CalibrationReports/README.md +2 -2
- data/lib/measures/CalibrationReports/measure.rb +1 -1
- data/lib/measures/CalibrationReports/measure.xml +11 -11
- data/lib/measures/CalibrationReportsEnhanced/LICENSE.md +1 -1
- data/lib/measures/CalibrationReportsEnhanced/measure.rb +2 -2
- data/lib/measures/CalibrationReportsEnhanced/measure.xml +18 -17
- data/lib/measures/CoilCoolingDXSingleSpeedMultiplier/LICENSE.md +1 -1
- data/lib/measures/CoilCoolingDXSingleSpeedMultiplier/measure.rb +1 -1
- data/lib/measures/CoilCoolingDXSingleSpeedMultiplier/measure.xml +14 -13
- data/lib/measures/CoilCoolingDXSingleSpeedPercentChange/LICENSE.md +1 -1
- data/lib/measures/CoilCoolingDXSingleSpeedPercentChange/measure.rb +1 -1
- data/lib/measures/CoilCoolingDXSingleSpeedPercentChange/measure.xml +14 -13
- data/lib/measures/CoilCoolingDXTwoSpeedMultiplier/LICENSE.md +1 -1
- data/lib/measures/CoilCoolingDXTwoSpeedMultiplier/measure.rb +1 -1
- data/lib/measures/CoilCoolingDXTwoSpeedMultiplier/measure.xml +14 -13
- data/lib/measures/CoilCoolingDXTwoSpeedPercentChange/LICENSE.md +1 -1
- data/lib/measures/CoilCoolingDXTwoSpeedPercentChange/measure.rb +1 -1
- data/lib/measures/CoilCoolingDXTwoSpeedPercentChange/measure.xml +14 -13
- data/lib/measures/CoilCoolingWaterMultiplier/LICENSE.md +1 -1
- data/lib/measures/CoilCoolingWaterMultiplier/measure.rb +1 -1
- data/lib/measures/CoilCoolingWaterMultiplier/measure.xml +14 -13
- data/lib/measures/CoilCoolingWaterPercentChange/LICENSE.md +1 -1
- data/lib/measures/CoilCoolingWaterPercentChange/measure.rb +1 -1
- data/lib/measures/CoilCoolingWaterPercentChange/measure.xml +14 -13
- data/lib/measures/CoilHeatingElectricMultiplier/LICENSE.md +1 -1
- data/lib/measures/CoilHeatingElectricMultiplier/measure.rb +1 -1
- data/lib/measures/CoilHeatingElectricMultiplier/measure.xml +14 -13
- data/lib/measures/CoilHeatingElectricPercentChange/LICENSE.md +1 -1
- data/lib/measures/CoilHeatingElectricPercentChange/measure.rb +1 -1
- data/lib/measures/CoilHeatingElectricPercentChange/measure.xml +14 -13
- data/lib/measures/CoilHeatingGasMultiplier/LICENSE.md +1 -1
- data/lib/measures/CoilHeatingGasMultiplier/measure.rb +1 -1
- data/lib/measures/CoilHeatingGasMultiplier/measure.xml +14 -13
- data/lib/measures/CoilHeatingGasPercentChange/LICENSE.md +1 -1
- data/lib/measures/CoilHeatingGasPercentChange/measure.rb +1 -1
- data/lib/measures/CoilHeatingGasPercentChange/measure.xml +14 -13
- data/lib/measures/CoilHeatingWaterMultiplier/LICENSE.md +1 -1
- data/lib/measures/CoilHeatingWaterMultiplier/measure.rb +1 -1
- data/lib/measures/CoilHeatingWaterMultiplier/measure.xml +14 -13
- data/lib/measures/CoilHeatingWaterPercentChange/LICENSE.md +1 -1
- data/lib/measures/CoilHeatingWaterPercentChange/measure.rb +1 -1
- data/lib/measures/CoilHeatingWaterPercentChange/measure.xml +14 -13
- data/lib/measures/ConstructionLayerZeroMaterialProperties/LICENSE.md +1 -1
- data/lib/measures/ConstructionLayerZeroMaterialProperties/measure.rb +1 -1
- data/lib/measures/ConstructionLayerZeroMaterialProperties/measure.xml +12 -11
- data/lib/measures/ElectricBaseboardEfficiencyAndCapacity/LICENSE.md +1 -1
- data/lib/measures/ElectricBaseboardEfficiencyAndCapacity/measure.rb +1 -1
- data/lib/measures/ElectricBaseboardEfficiencyAndCapacity/measure.xml +12 -11
- data/lib/measures/ExteriorWallThermalPropertiesMultiplier/LICENSE.md +1 -1
- data/lib/measures/ExteriorWallThermalPropertiesMultiplier/measure.rb +3 -3
- data/lib/measures/ExteriorWallThermalPropertiesMultiplier/measure.xml +25 -13
- data/lib/measures/ExteriorWallThermalPropertiesPercentChange/LICENSE.md +1 -1
- data/lib/measures/ExteriorWallThermalPropertiesPercentChange/measure.rb +3 -3
- data/lib/measures/ExteriorWallThermalPropertiesPercentChange/measure.xml +25 -13
- data/lib/measures/FansMultiplier/LICENSE.md +1 -1
- data/lib/measures/FansMultiplier/measure.rb +1 -1
- data/lib/measures/FansMultiplier/measure.xml +14 -13
- data/lib/measures/FansPercentChange/LICENSE.md +1 -1
- data/lib/measures/FansPercentChange/measure.rb +1 -1
- data/lib/measures/FansPercentChange/measure.xml +14 -13
- data/lib/measures/GeneralCalibrationMeasureMultiplier/LICENSE.md +1 -1
- data/lib/measures/GeneralCalibrationMeasureMultiplier/measure.rb +1 -1
- data/lib/measures/GeneralCalibrationMeasureMultiplier/measure.xml +16 -15
- data/lib/measures/GeneralCalibrationMeasurePercentChange/LICENSE.md +1 -1
- data/lib/measures/GeneralCalibrationMeasurePercentChange/measure.rb +1 -1
- data/lib/measures/GeneralCalibrationMeasurePercentChange/measure.xml +16 -15
- data/lib/measures/HardSizeHvac/LICENSE.md +1 -1
- data/lib/measures/HardSizeHvac/measure.rb +9 -7
- data/lib/measures/HardSizeHvac/measure.xml +26 -13
- data/lib/measures/RValueOfInsulationForConstructionMultiplier/LICENSE.md +1 -1
- data/lib/measures/RValueOfInsulationForConstructionMultiplier/measure.rb +1 -1
- data/lib/measures/RValueOfInsulationForConstructionMultiplier/measure.xml +12 -11
- data/lib/measures/RValueOfInsulationForConstructionPercentageChange/LICENSE.md +1 -1
- data/lib/measures/RValueOfInsulationForConstructionPercentageChange/measure.rb +1 -1
- data/lib/measures/RValueOfInsulationForConstructionPercentageChange/measure.xml +12 -11
- data/lib/measures/RoofThermalPropertiesMultiplier/LICENSE.md +1 -1
- data/lib/measures/RoofThermalPropertiesMultiplier/measure.rb +3 -3
- data/lib/measures/RoofThermalPropertiesMultiplier/measure.xml +25 -13
- data/lib/measures/RoofThermalPropertiesPercentChange/LICENSE.md +1 -1
- data/lib/measures/RoofThermalPropertiesPercentChange/measure.rb +3 -3
- data/lib/measures/RoofThermalPropertiesPercentChange/measure.xml +25 -13
- data/lib/measures/TimeseriesObjectiveFunction/LICENSE.md +1 -1
- data/lib/measures/TimeseriesObjectiveFunction/README.md +171 -5
- data/lib/measures/TimeseriesObjectiveFunction/measure.rb +2 -2
- data/lib/measures/TimeseriesObjectiveFunction/measure.xml +6 -81
- data/lib/measures/TimeseriesObjectiveFunction/resources/report.html.erb +4 -1
- data/lib/measures/TimeseriesPlot/LICENSE.md +1 -1
- data/lib/measures/TimeseriesPlot/README.md +35 -5
- data/lib/measures/TimeseriesPlot/measure.rb +2 -2
- data/lib/measures/TimeseriesPlot/measure.xml +11 -26
- data/lib/measures/TimeseriesPlot/resources/report.html.erb +4 -1
- data/lib/measures/WaterHeaterMixedMultiplier/LICENSE.md +1 -1
- data/lib/measures/WaterHeaterMixedMultiplier/measure.rb +1 -1
- data/lib/measures/WaterHeaterMixedMultiplier/measure.xml +14 -13
- data/lib/measures/WaterHeaterMixedPercentChange/LICENSE.md +1 -1
- data/lib/measures/WaterHeaterMixedPercentChange/measure.rb +1 -1
- data/lib/measures/WaterHeaterMixedPercentChange/measure.xml +14 -13
- data/lib/measures/{zone_report → inspect_and_edit_parametric_schedules}/LICENSE.md +1 -1
- data/lib/measures/inspect_and_edit_parametric_schedules/README.md +41 -0
- data/lib/measures/inspect_and_edit_parametric_schedules/README.md.erb +53 -0
- data/lib/measures/inspect_and_edit_parametric_schedules/docs/apply_measures_now.png +0 -0
- data/lib/measures/inspect_and_edit_parametric_schedules/measure.rb +224 -0
- data/lib/measures/inspect_and_edit_parametric_schedules/measure.xml +125 -0
- data/lib/measures/shift_hours_of_operation/LICENSE.md +27 -0
- data/lib/measures/shift_hours_of_operation/README.md +147 -0
- data/lib/measures/{zone_report → shift_hours_of_operation}/README.md.erb +5 -0
- data/lib/measures/shift_hours_of_operation/docs/.gitkeep +0 -0
- data/lib/measures/shift_hours_of_operation/measure.rb +525 -0
- data/lib/measures/shift_hours_of_operation/measure.xml +280 -0
- data/lib/openstudio/calibration/extension.rb +1 -1
- data/lib/openstudio/calibration/version.rb +2 -2
- data/lib/openstudio/calibration.rb +1 -1
- data/lib/openstudio-calibration.rb +1 -1
- data/openstudio-calibration.gemspec +3 -3
- metadata +23 -17
- data/lib/measures/zone_report/README.md +0 -26
- data/lib/measures/zone_report/measure.rb +0 -706
- data/lib/measures/zone_report/measure.xml +0 -69
- data/lib/measures/zone_report/resources/report.html.in +0 -342
@@ -0,0 +1,525 @@
|
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
|
3
|
+
# All rights reserved.
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# (1) Redistributions of source code must retain the above copyright notice,
|
8
|
+
# this list of conditions and the following disclaimer.
|
9
|
+
#
|
10
|
+
# (2) Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
#
|
14
|
+
# (3) Neither the name of the copyright holder nor the names of any contributors
|
15
|
+
# may be used to endorse or promote products derived from this software without
|
16
|
+
# specific prior written permission from the respective party.
|
17
|
+
#
|
18
|
+
# (4) Other than as required in clauses (1) and (2), distributions in any form
|
19
|
+
# of modifications or other derivative works may not use the "OpenStudio"
|
20
|
+
# trademark, "OS", "os", or any other confusingly similar designation without
|
21
|
+
# specific prior written permission from Alliance for Sustainable Energy, LLC.
|
22
|
+
#
|
23
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
|
24
|
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
25
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
|
27
|
+
# UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
|
28
|
+
# THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
29
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
30
|
+
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
31
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
32
|
+
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
33
|
+
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
34
|
+
# *******************************************************************************
|
35
|
+
|
36
|
+
# insert your copyright here
|
37
|
+
|
38
|
+
# see the URL below for information on how to write OpenStudio measures
|
39
|
+
# http://nrel.github.io/OpenStudio-user-documentation/reference/measure_writing_guide/
|
40
|
+
|
41
|
+
require 'openstudio-standards'
|
42
|
+
|
43
|
+
# load OpenStudio measure libraries from openstudio-extension gem
|
44
|
+
require 'openstudio-extension'
|
45
|
+
require 'openstudio/extension/core/os_lib_helper_methods'
|
46
|
+
|
47
|
+
# start the measure
|
48
|
+
class ShiftHoursOfOperation < OpenStudio::Measure::ModelMeasure
|
49
|
+
# resource file modules
|
50
|
+
include OsLib_HelperMethods
|
51
|
+
|
52
|
+
# human readable name
|
53
|
+
def name
|
54
|
+
# Measure name should be the title case of the class name.
|
55
|
+
return 'Shift Hours of Operation'
|
56
|
+
end
|
57
|
+
|
58
|
+
# human readable description
|
59
|
+
def description
|
60
|
+
return 'This measure will infer the hours of operation for the building and then will shift the start of the hours of operation and change the duration of the hours of operation. In an alternate workflow you can directly pass in target start and duration rather than a shift and delta. Inputs can vary for weekday, Saturday, and Sunday. if a day does not have any hours of operation to start with increasing hours of operation may not have any impact as the auto generated data may not know what to do during operating hours. Future version may be able to borrow a profile formula but would probably require additional user arguments.'
|
61
|
+
end
|
62
|
+
|
63
|
+
# human readable description of modeling approach
|
64
|
+
def modeler_description
|
65
|
+
return 'This will only impact schedule rulesets. It will use methods in openstudio-standards to infer hours of operation, develop a parametric formula for all of the ruleset schedules, alter the hours of operation inputs to that formula and then re-apply the schedules. Input is expose to set ramp frequency of the resulting schedules. If inputs are such that no changes are requested, bypass the measure with NA so that it will not be parameterized. An advanced option for this measure would be bool to use hours of operation from OSM schedule ruleset hours of operation instead of inferring from standards. This should allow different parts of the building to have different hours of operation in the seed model.'
|
66
|
+
end
|
67
|
+
|
68
|
+
# define the arguments that the user will input
|
69
|
+
def arguments(model)
|
70
|
+
args = OpenStudio::Measure::OSArgumentVector.new
|
71
|
+
|
72
|
+
# delta hoo_start for weekdays
|
73
|
+
hoo_start_weekday = OpenStudio::Measure::OSArgument.makeDoubleArgument('hoo_start_weekday', true)
|
74
|
+
hoo_start_weekday.setDisplayName('Shift the weekday start of hours of operation.')
|
75
|
+
hoo_start_weekday.setDescription('Use decimal hours so an 1 hour and 15 minute shift would be 1.25. Positive value moves the hour of operation later')
|
76
|
+
hoo_start_weekday.setDefaultValue(0.0)
|
77
|
+
hoo_start_weekday.setUnits('Hours')
|
78
|
+
args << hoo_start_weekday
|
79
|
+
|
80
|
+
# delta hoo_dur for weekday
|
81
|
+
hoo_dur_weekday = OpenStudio::Measure::OSArgument.makeDoubleArgument('hoo_dur_weekday', true)
|
82
|
+
hoo_dur_weekday.setDisplayName('Extend the weekday of hours of operation.')
|
83
|
+
hoo_dur_weekday.setDescription('Use decimal hours so an 1 hour and 15 minute would be 1.25. Positive value makes the hour of operation longer.')
|
84
|
+
hoo_dur_weekday .setDefaultValue(0.0)
|
85
|
+
hoo_dur_weekday.setUnits('Hours')
|
86
|
+
args << hoo_dur_weekday
|
87
|
+
|
88
|
+
# TODO: - could include every day of the week
|
89
|
+
|
90
|
+
# delta hoo_start for saturdays
|
91
|
+
hoo_start_saturday = OpenStudio::Measure::OSArgument.makeDoubleArgument('hoo_start_saturday', true)
|
92
|
+
hoo_start_saturday.setDisplayName('Shift the saturday start of hours of operation.')
|
93
|
+
hoo_start_saturday.setDescription('Use decimal hours so an 1 hour and 15 minute shift would be 1.25. Positive value moves the hour of operation later')
|
94
|
+
hoo_start_saturday.setDefaultValue(0.0)
|
95
|
+
hoo_start_saturday.setUnits('Hours')
|
96
|
+
args << hoo_start_saturday
|
97
|
+
|
98
|
+
# delta hoo_dur for saturday
|
99
|
+
hoo_dur_saturday = OpenStudio::Measure::OSArgument.makeDoubleArgument('hoo_dur_saturday', true)
|
100
|
+
hoo_dur_saturday.setDisplayName('Extend the saturday of hours of operation.')
|
101
|
+
hoo_dur_saturday.setDescription('Use decimal hours so an 1 hour and 15 minute would be 1.25. Positive value makes the hour of operation longer.')
|
102
|
+
hoo_dur_saturday.setDefaultValue(0.0)
|
103
|
+
hoo_dur_saturday.setUnits('Hours')
|
104
|
+
args << hoo_dur_saturday
|
105
|
+
|
106
|
+
# delta hoo_start for sundays
|
107
|
+
hoo_start_sunday = OpenStudio::Measure::OSArgument.makeDoubleArgument('hoo_start_sunday', true)
|
108
|
+
hoo_start_sunday.setDisplayName('Shift the sunday start of hours of operation.')
|
109
|
+
hoo_start_sunday.setDescription('Use decimal hours so an 1 hour and 15 minute shift would be 1.25. Positive value moves the hour of operation later')
|
110
|
+
hoo_start_sunday.setDefaultValue(0.0)
|
111
|
+
hoo_start_sunday.setUnits('Hours')
|
112
|
+
args << hoo_start_sunday
|
113
|
+
|
114
|
+
# delta hoo_dur for sunday
|
115
|
+
hoo_dur_sunday = OpenStudio::Measure::OSArgument.makeDoubleArgument('hoo_dur_sunday', true)
|
116
|
+
hoo_dur_sunday.setDisplayName('Extend the sunday of hours of operation.')
|
117
|
+
hoo_dur_sunday.setDescription('Use decimal hours so an 1 hour and 15 minute would be 1.25. Positive value makes the hour of operation longer.')
|
118
|
+
hoo_dur_sunday.setDefaultValue(0.0)
|
119
|
+
hoo_dur_sunday.setUnits('Hours')
|
120
|
+
args << hoo_dur_sunday
|
121
|
+
|
122
|
+
# TODO: - could include start and end days to have delta or absolute values applied to. (maybe decimal between 1.0 and 13.0 month where 3.50 would be March 15th)
|
123
|
+
|
124
|
+
# make an argument for delta_values
|
125
|
+
delta_values = OpenStudio::Measure::OSArgument.makeBoolArgument('delta_values', true)
|
126
|
+
delta_values.setDisplayName('Hours of operation values treated as deltas')
|
127
|
+
delta_values.setDescription('When this is true the hours of operation start and duration represent a delta from the original model values. When switched to false they represent absolute values.')
|
128
|
+
delta_values.setDefaultValue(true)
|
129
|
+
args << delta_values
|
130
|
+
|
131
|
+
# make an argument for infer_parametric_schedules
|
132
|
+
infer_parametric_schedules = OpenStudio::Measure::OSArgument.makeBoolArgument('infer_parametric_schedules', true)
|
133
|
+
infer_parametric_schedules.setDisplayName('Dynamically generate parametric schedules from current ruleset schedules.')
|
134
|
+
infer_parametric_schedules.setDescription('When this is true the parametric schedule formulas and hours of operation will be generated from the existing model schedules. When false it expects the model already has parametric formulas stored.')
|
135
|
+
infer_parametric_schedules.setDefaultValue(true)
|
136
|
+
args << infer_parametric_schedules
|
137
|
+
|
138
|
+
# delta hoo_start for sundays
|
139
|
+
fraction_of_daily_occ_range = OpenStudio::Measure::OSArgument.makeDoubleArgument('fraction_of_daily_occ_range', true)
|
140
|
+
fraction_of_daily_occ_range.setDisplayName('Fraction of Daily Occupancy Range.')
|
141
|
+
fraction_of_daily_occ_range.setDescription('This determine what fraction of occupancy be considered operating conditions. This fraction is normalized to expanded to range seen over the full year and does not necessary equal fraction of design occupancy. This value should be between 0 and 1.0 and is only used if dynamically generated parametric schedules are used.')
|
142
|
+
fraction_of_daily_occ_range.setDefaultValue(0.25)
|
143
|
+
fraction_of_daily_occ_range.setUnits('Hours')
|
144
|
+
args << fraction_of_daily_occ_range
|
145
|
+
|
146
|
+
# argument to choose hour of operation variable method
|
147
|
+
choices = OpenStudio::StringVector.new
|
148
|
+
choices << 'fractional'
|
149
|
+
choices << 'hours'
|
150
|
+
hoo_var_method = OpenStudio::Measure::OSArgument.makeChoiceArgument('hoo_var_method', choices, true)
|
151
|
+
hoo_var_method.setDisplayName('Hours of Operation Variable Method for Scheudle Profile Formula.')
|
152
|
+
hoo_var_method.setDescription('If dynamically generate parametric schedules from current ruleset scheudles is selected ,this argument is used to determine if the schedule profile formulas define time of points in a profile as a a specific delta from the star, middle, or end of the horus of operation, or if the delta is fractaionl percentate of the horus fo operation ro non-operation/vacant time.')
|
153
|
+
hoo_var_method.setDefaultValue('fractional')
|
154
|
+
args << hoo_var_method
|
155
|
+
|
156
|
+
# make an argument for target_hoo_from_model
|
157
|
+
# Should only be true when infer_parametric_schedules is false
|
158
|
+
target_hoo_from_model = OpenStudio::Measure::OSArgument.makeBoolArgument('target_hoo_from_model', true)
|
159
|
+
target_hoo_from_model.setDisplayName('Use model hours of operation as target')
|
160
|
+
target_hoo_from_model.setDescription('The default behavior is for this to be false. This can not be used unless Dynamically generate parametric schedules from current ruleset schedules is set to false and if the schedules in the model already have parametric profiles. When changed to true all of the hours of operation start and duration values will be ignored as the bool to treat those values as relative or absolute. Instead the hours of operation schedules for the model will be used.')
|
161
|
+
target_hoo_from_model.setDefaultValue(false)
|
162
|
+
args << target_hoo_from_model
|
163
|
+
|
164
|
+
# TODO: - add argument for step frequency, which is hours per step (should be fractional 1 or less generally).
|
165
|
+
# For now it defaults to simulation timestep
|
166
|
+
|
167
|
+
return args
|
168
|
+
end
|
169
|
+
|
170
|
+
# get model hoo info
|
171
|
+
def hoo_summary(model, runner, standard)
|
172
|
+
hoo_summary_hash = {}
|
173
|
+
hoo_summary_hash[:zero_hoo] = []
|
174
|
+
hoo_summary_hash[:final_hoo_start_range] = []
|
175
|
+
hoo_summary_hash[:final_hoo_dur_range] = []
|
176
|
+
model.getSpaces.sort.each do |space|
|
177
|
+
default_sch_type = OpenStudio::Model::DefaultScheduleType.new('HoursofOperationSchedule')
|
178
|
+
hours_of_operation = space.getDefaultSchedule(default_sch_type)
|
179
|
+
if !hours_of_operation.is_initialized
|
180
|
+
runner.registerWarning("Hours of Operation Schedule is not set for #{space.name}.")
|
181
|
+
next
|
182
|
+
end
|
183
|
+
hours_of_operation_hash = standard.space_hours_of_operation(space)
|
184
|
+
hours_of_operation_hash.each do |hoo_key, val|
|
185
|
+
if val[:hoo_hours] == 0.0
|
186
|
+
hoo_summary_hash[:zero_hoo] << val[:hoo_hours]
|
187
|
+
else
|
188
|
+
hoo_summary_hash[:final_hoo_dur_range] << val[:hoo_hours]
|
189
|
+
hoo_summary_hash[:final_hoo_start_range] << val[:hoo_start]
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
return hoo_summary_hash
|
195
|
+
end
|
196
|
+
|
197
|
+
# process hoo schedules for various days of the week
|
198
|
+
# todo - when date range arg is used and not full year will never want to change default profile
|
199
|
+
def process_hoo(used_hoo_sch_sets, model, runner, args, days_of_week, hoo_start_dows, hoo_dur_dows)
|
200
|
+
# profiles added to this will be processed
|
201
|
+
altered_schedule_days = {} # key is profile value is original index position defined in used_hoo_sch_sets
|
202
|
+
|
203
|
+
# loop through horus of operation schedules
|
204
|
+
used_hoo_sch_sets.uniq.each do |hoo_sch, hours_of_operation_hash|
|
205
|
+
if !hoo_sch.to_ScheduleRuleset.is_initialized
|
206
|
+
runner.registerWarning("#{hoo_sch.name} is not schedule schedule ruleset, will not be altered by this method.")
|
207
|
+
next
|
208
|
+
end
|
209
|
+
hoo_sch = hoo_sch.to_ScheduleRuleset.get
|
210
|
+
|
211
|
+
year_description = hoo_sch.model.yearDescription.get
|
212
|
+
year = year_description.assumedYear
|
213
|
+
year_start_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new('January'), 1, year)
|
214
|
+
year_end_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new('December'), 31, year)
|
215
|
+
|
216
|
+
orig_profile_indexes_used = hoo_sch.getActiveRuleIndices(year_start_date, year_end_date)
|
217
|
+
orig_num_days_default_used = orig_profile_indexes_used.count(-1)
|
218
|
+
if orig_num_days_default_used > 0
|
219
|
+
default_prof = hoo_sch.defaultDaySchedule
|
220
|
+
|
221
|
+
# clone default profile as rule that sits above it so it can be evauluated and used if needed
|
222
|
+
new_prof = default_prof.clone(model).to_ScheduleDay.get
|
223
|
+
new_rule = OpenStudio::Model::ScheduleRule.new(hoo_sch, new_prof)
|
224
|
+
hoo_sch.setScheduleRuleIndex(new_rule, hoo_sch.scheduleRules.size - 1)
|
225
|
+
|
226
|
+
# set days of week for clone to match days of week passed into the method
|
227
|
+
if days_of_week.include?('mon')
|
228
|
+
new_rule.setApplyMonday(true)
|
229
|
+
end
|
230
|
+
if days_of_week.include?('tue')
|
231
|
+
new_rule.setApplyTuesday(true)
|
232
|
+
end
|
233
|
+
if days_of_week.include?('wed')
|
234
|
+
new_rule.setApplyWednesday(true)
|
235
|
+
end
|
236
|
+
if days_of_week.include?('thur')
|
237
|
+
new_rule.setApplyThursday(true)
|
238
|
+
end
|
239
|
+
if days_of_week.include?('fri')
|
240
|
+
new_rule.setApplyFriday(true)
|
241
|
+
end
|
242
|
+
if days_of_week.include?('sat')
|
243
|
+
new_rule.setApplySaturday(true)
|
244
|
+
end
|
245
|
+
if days_of_week.include?('sun')
|
246
|
+
new_rule.setApplySunday(true)
|
247
|
+
end
|
248
|
+
|
249
|
+
# check if default days are used at all
|
250
|
+
profile_indexes_used = hoo_sch.getActiveRuleIndices(year_start_date, year_end_date)
|
251
|
+
num_days_new_profile_used = profile_indexes_used.count(hoo_sch.scheduleRules.size - 1)
|
252
|
+
if !profile_indexes_used.uniq.include?(-1) && num_days_new_profile_used > 0
|
253
|
+
# don't need new profile, can use default
|
254
|
+
new_rule.remove
|
255
|
+
altered_schedule_days[hoo_sch.defaultDaySchedule] = -1
|
256
|
+
elsif num_days_new_profile_used == 0.0
|
257
|
+
# can remove cloned rule and skip the default profile (don't pass into array)
|
258
|
+
new_rule.remove
|
259
|
+
else
|
260
|
+
altered_schedule_days[new_rule.daySchedule] = -1 # use hoo that was applicable to the default before it was cloned
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
# use this to link to hoo from hours_of_operation_hash
|
265
|
+
counter_of_orig_index = hours_of_operation_hash.size - 2 # this is not impacted by cloning that may have happened above
|
266
|
+
|
267
|
+
hoo_sch.scheduleRules.reverse.each do |rule|
|
268
|
+
# inspect days of the week
|
269
|
+
actual_days_of_week_for_profile = []
|
270
|
+
if rule.applyMonday then actual_days_of_week_for_profile << 'mon' end
|
271
|
+
if rule.applyTuesday then actual_days_of_week_for_profile << 'tue' end
|
272
|
+
if rule.applyWednesday then actual_days_of_week_for_profile << 'wed' end
|
273
|
+
if rule.applyThursday then actual_days_of_week_for_profile << 'thur' end
|
274
|
+
if rule.applyFriday then actual_days_of_week_for_profile << 'fri' end
|
275
|
+
if rule.applySaturday then actual_days_of_week_for_profile << 'sat' end
|
276
|
+
if rule.applySunday then actual_days_of_week_for_profile << 'sun' end
|
277
|
+
|
278
|
+
# if an exact match for the rules passed in are met, this rule can be edited in place (update later for date range)
|
279
|
+
day_of_week_intersect = days_of_week & actual_days_of_week_for_profile
|
280
|
+
current_rule_index = rule.ruleIndex
|
281
|
+
if days_of_week == actual_days_of_week_for_profile
|
282
|
+
altered_schedule_days[rule.daySchedule] = counter_of_orig_index
|
283
|
+
|
284
|
+
# if this rule contains the requested days of the week and another then a clone should be made above this with only the requested days of the week that are also already on for this rule
|
285
|
+
elsif !day_of_week_intersect.empty?
|
286
|
+
|
287
|
+
# clone default profile as rule that sits above it so it can be evaluated and used if needed
|
288
|
+
new_rule = rule.clone(model).to_ScheduleRule.get
|
289
|
+
hoo_sch.setScheduleRuleIndex(new_rule, current_rule_index) # the cloned rule should be just above what was cloned
|
290
|
+
|
291
|
+
# update days of week for rule
|
292
|
+
if day_of_week_intersect.include?('mon')
|
293
|
+
new_rule.setApplyMonday(true)
|
294
|
+
else
|
295
|
+
new_rule.setApplyMonday(false)
|
296
|
+
end
|
297
|
+
if day_of_week_intersect.include?('tue')
|
298
|
+
new_rule.setApplyTuesday(true)
|
299
|
+
else
|
300
|
+
new_rule.setApplyTuesday(false)
|
301
|
+
end
|
302
|
+
if day_of_week_intersect.include?('wed')
|
303
|
+
new_rule.setApplyWednesday(true)
|
304
|
+
else
|
305
|
+
new_rule.setApplyWednesday(false)
|
306
|
+
end
|
307
|
+
if day_of_week_intersect.include?('thur')
|
308
|
+
new_rule.setApplyThursday(true)
|
309
|
+
else
|
310
|
+
new_rule.setApplyThursday(false)
|
311
|
+
end
|
312
|
+
if day_of_week_intersect.include?('fri')
|
313
|
+
new_rule.setApplyFriday(true)
|
314
|
+
else
|
315
|
+
new_rule.setApplyFriday(false)
|
316
|
+
end
|
317
|
+
if day_of_week_intersect.include?('sat')
|
318
|
+
new_rule.setApplySaturday(true)
|
319
|
+
else
|
320
|
+
new_rule.setApplySaturday(false)
|
321
|
+
end
|
322
|
+
if day_of_week_intersect.include?('sun')
|
323
|
+
new_rule.setApplySunday(true)
|
324
|
+
else
|
325
|
+
new_rule.setApplySunday(false)
|
326
|
+
end
|
327
|
+
|
328
|
+
# add to array
|
329
|
+
altered_schedule_days[new_rule.daySchedule] = counter_of_orig_index
|
330
|
+
end
|
331
|
+
|
332
|
+
# adjust the count used to find hoo from hours_of_operation_hash
|
333
|
+
counter_of_orig_index -= 1
|
334
|
+
end
|
335
|
+
runner.registerInfo("For #{hoo_sch.name} #{days_of_week.inspect} #{altered_schedule_days.size} profiles will be processed.")
|
336
|
+
|
337
|
+
# convert altered_schedule_days to hash where key is profile and value is key of index in hours_of_operation_hash
|
338
|
+
|
339
|
+
# loop through profiles to changes
|
340
|
+
altered_schedule_days.each do |new_profile, hoo_hash_index|
|
341
|
+
# gather info and edit selected profile
|
342
|
+
if args['delta_values']
|
343
|
+
orig_hoo_start = hours_of_operation_hash[hoo_hash_index][:hoo_start]
|
344
|
+
orig_hoo_dur = hours_of_operation_hash[hoo_hash_index][:hoo_hours]
|
345
|
+
|
346
|
+
# check for duration grater than 24 or lower than 0
|
347
|
+
max_dur_delta = 24 - orig_hoo_dur
|
348
|
+
min_dur_delta = orig_hoo_dur * -1.0
|
349
|
+
if hoo_dur_dows > max_dur_delta
|
350
|
+
target_dur = 24.0
|
351
|
+
runner.registerWarning("For profile in #{hoo_sch.name} duration is being capped at 24 hours.")
|
352
|
+
elsif hoo_dur_dows < min_dur_delta
|
353
|
+
target_dur = 0.0
|
354
|
+
runner.registerWarning("For profile in #{hoo_sch.name} duration is being limited to a low of 0 hours.")
|
355
|
+
else
|
356
|
+
target_dur = hoo_dur_dows + orig_hoo_dur
|
357
|
+
end
|
358
|
+
|
359
|
+
# setup new hoo values with delta
|
360
|
+
if orig_hoo_start + hoo_start_dows <= 24.0
|
361
|
+
new_hoo_start = orig_hoo_start + hoo_start_dows
|
362
|
+
else
|
363
|
+
new_hoo_start = orig_hoo_start + hoo_start_dows - 24.0
|
364
|
+
end
|
365
|
+
if new_hoo_start + hoo_dur_dows + orig_hoo_dur <= 24.0
|
366
|
+
new_hoo_end = new_hoo_start + target_dur
|
367
|
+
else
|
368
|
+
new_hoo_end = new_hoo_start + target_dur - 24.0
|
369
|
+
end
|
370
|
+
else
|
371
|
+
new_hoo_start = hoo_start_dows
|
372
|
+
target_dur = hoo_dur_dows
|
373
|
+
if new_hoo_start + target_dur < 24.0
|
374
|
+
new_hoo_end = new_hoo_start + target_dur
|
375
|
+
elsif new_hoo_start + target_dur == 24.0
|
376
|
+
new_hoo_end = 0.0
|
377
|
+
else # greater than 24
|
378
|
+
new_hoo_end = new_hoo_start + target_dur - 24.0
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
# setup hoo start time
|
383
|
+
target_start_hr = new_hoo_start.truncate
|
384
|
+
target_start_min = ((new_hoo_start - target_start_hr) * 60.0).truncate
|
385
|
+
target_start_time = OpenStudio::Time.new(0, target_start_hr, target_start_min, 0)
|
386
|
+
|
387
|
+
# setup hoo end time
|
388
|
+
target_end_hr = new_hoo_end.truncate
|
389
|
+
target_end_min = ((new_hoo_end - target_end_hr) * 60.0).truncate
|
390
|
+
target_end_time = OpenStudio::Time.new(0, target_end_hr, target_end_min, 0)
|
391
|
+
|
392
|
+
# adding new values
|
393
|
+
new_profile.clearValues
|
394
|
+
if target_dur < 24
|
395
|
+
new_profile.addValue(target_start_time, 0)
|
396
|
+
end
|
397
|
+
if target_dur > 0
|
398
|
+
new_profile.addValue(target_end_time, 1)
|
399
|
+
end
|
400
|
+
os_time_24 = OpenStudio::Time.new(0, 24, 0, 0)
|
401
|
+
if target_end_time > target_start_time || target_start_time == os_time_24
|
402
|
+
new_profile.addValue(os_time_24, 0)
|
403
|
+
elsif target_end_time < target_start_time
|
404
|
+
new_profile.addValue(os_time_24, 1)
|
405
|
+
else # they are equal
|
406
|
+
if target_dur == 24.0
|
407
|
+
new_profile.addValue(os_time_24, 1)
|
408
|
+
else
|
409
|
+
new_profile.addValue(os_time_24, 0)
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
return altered_schedule_days
|
416
|
+
end
|
417
|
+
|
418
|
+
# define what happens when the measure is run
|
419
|
+
def run(model, runner, user_arguments)
|
420
|
+
super(model, runner, user_arguments)
|
421
|
+
|
422
|
+
# assign the user inputs to variables
|
423
|
+
args = OsLib_HelperMethods.createRunVariables(runner, model, user_arguments, arguments(model))
|
424
|
+
if !args then return false end
|
425
|
+
|
426
|
+
# check expected values of double arguments
|
427
|
+
fraction = OsLib_HelperMethods.checkDoubleAndIntegerArguments(runner, user_arguments, 'min' => 0.0, 'max' => 1.0, 'min_eq_bool' => true, 'max_eq_bool' => true, 'arg_array' => ['fraction_of_daily_occ_range'])
|
428
|
+
|
429
|
+
neg_24__24 = ['hoo_start_weekday',
|
430
|
+
'hoo_dur_weekday',
|
431
|
+
'hoo_start_saturday',
|
432
|
+
'hoo_dur_saturday',
|
433
|
+
'hoo_start_sunday',
|
434
|
+
'hoo_dur_sunday']
|
435
|
+
time_hours = OsLib_HelperMethods.checkDoubleAndIntegerArguments(runner, user_arguments, 'min' => -24.0, 'max' => 24.0, 'min_eq_bool' => true, 'max_eq_bool' => true, 'arg_array' => neg_24__24)
|
436
|
+
|
437
|
+
# setup log messages that will come from standards
|
438
|
+
OsLib_HelperMethods.setup_log_msgs(runner, true) # bool is debug
|
439
|
+
|
440
|
+
# load standards
|
441
|
+
standard = Standard.build('90.1-2004') # selected template doesn't matter
|
442
|
+
|
443
|
+
if args['infer_parametric_schedules']
|
444
|
+
# infer hours of operation for the building
|
445
|
+
# @param fraction_of_daily_occ_range [Double] fraction above/below daily min range required to start and end hours of operation
|
446
|
+
occ_fraction = args['fraction_of_daily_occ_range']
|
447
|
+
standard.model_infer_hours_of_operation_building(model, fraction_of_daily_occ_range: occ_fraction, gen_occ_profile: true)
|
448
|
+
runner.registerInfo('Inferring initial hours of operation for the building and generating parametric profile formulas.')
|
449
|
+
|
450
|
+
# report back hours of operation
|
451
|
+
initial_hoo_range = []
|
452
|
+
hours_of_operation_hash_test = standard.space_hours_of_operation(model.getSpaces.first)
|
453
|
+
hours_of_operation_hash_test.each do |hoo_key, val|
|
454
|
+
initial_hoo_range << val[:hoo_hours]
|
455
|
+
runner.registerInfo("For Profile Index #{hoo_key} hours of operation run for #{val[:hoo_hours]} hours, from #{val[:hoo_start]} to #{val[:hoo_end]} and is used for #{val[:days_used].size} days of the year.")
|
456
|
+
end
|
457
|
+
|
458
|
+
# model_setup_parametric_schedules
|
459
|
+
standard.model_setup_parametric_schedules(model, gather_data_only: false, hoo_var_method: args['hoo_var_method'])
|
460
|
+
end
|
461
|
+
|
462
|
+
# report initial condition of model
|
463
|
+
hoo_summary_hash = hoo_summary(model, runner, standard)
|
464
|
+
if !hoo_summary_hash[:zero_hoo].empty?
|
465
|
+
runner.registerInitialCondition("Across the building the non-zero hours of operation range from #{hoo_summary_hash[:final_hoo_dur_range].min} hours to #{hoo_summary_hash[:final_hoo_dur_range].max} hours. Start of hours of operation range from #{hoo_summary_hash[:final_hoo_start_range].min} to #{hoo_summary_hash[:final_hoo_start_range].max}. One or more hours of operation schedules used contain a profile with 0 hours of operation.")
|
466
|
+
else
|
467
|
+
runner.registerInitialCondition("Across the building the hours of operation range from #{hoo_summary_hash[:final_hoo_dur_range].min} hours to #{hoo_summary_hash[:final_hoo_dur_range].max} hours. Start of hours of operation range from #{hoo_summary_hash[:final_hoo_start_range].min} to #{hoo_summary_hash[:final_hoo_start_range].max}.")
|
468
|
+
end
|
469
|
+
|
470
|
+
# gather hours of operation schedules used by this model
|
471
|
+
used_hoo_sch_sets = {}
|
472
|
+
model.getSpaces.sort.each do |space|
|
473
|
+
default_sch_type = OpenStudio::Model::DefaultScheduleType.new('HoursofOperationSchedule')
|
474
|
+
hours_of_operation = space.getDefaultSchedule(default_sch_type)
|
475
|
+
if !hours_of_operation.is_initialized
|
476
|
+
runner.registerWarning("Hours of Operation Schedule is not set for #{space.name}.")
|
477
|
+
next
|
478
|
+
end
|
479
|
+
hours_of_operation_hash = standard.space_hours_of_operation(space)
|
480
|
+
used_hoo_sch_sets[hours_of_operation.get] = hours_of_operation_hash
|
481
|
+
end
|
482
|
+
|
483
|
+
# loop through and alter hours of operation schedules
|
484
|
+
runner.registerInfo("There are #{used_hoo_sch_sets.uniq.size} hours of operation schedules in the model to alter.")
|
485
|
+
|
486
|
+
# process weekday profiles
|
487
|
+
runner.registerInfo('Altering hours of operation schedules for weekday profiles')
|
488
|
+
weekday = process_hoo(used_hoo_sch_sets, model, runner, args, ['mon', 'tue', 'wed', 'thur', 'fri'], args['hoo_start_weekday'], args['hoo_dur_weekday'])
|
489
|
+
|
490
|
+
# process saturday profiles
|
491
|
+
runner.registerInfo('Altering hours of operation schedules for saturday profiles')
|
492
|
+
saturday = process_hoo(used_hoo_sch_sets, model, runner, args, ['sat'], args['hoo_start_saturday'], args['hoo_dur_saturday'])
|
493
|
+
|
494
|
+
# process sunday profiles
|
495
|
+
runner.registerInfo('Altering hours of operation schedules for sunday profiles')
|
496
|
+
sunday = process_hoo(used_hoo_sch_sets, model, runner, args, ['sun'], args['hoo_start_sunday'], args['hoo_dur_sunday'])
|
497
|
+
|
498
|
+
# TODO: - need to address this error when manipulating schedules
|
499
|
+
# [openstudio.standards.ScheduleRuleset] <1> Pre-interpolated processed hash for Large Office Bldg Equip Default Schedule has one or more out of order conflicts: [[3.5, 0.8], [4.5, 0.6], [5.0, 0.6], [7.0, 0.5], [9.0, 0.4], [6.0, 0.4], [10.0, 0.9], [16.5, 0.9], [17.5, 0.8], [18.5, 0.9], [21.5, 0.9]]. Method will stop because Error on Out of Order was set to true.
|
500
|
+
# model_build_parametric_schedules
|
501
|
+
parametric_schedules = standard.model_apply_parametric_schedules(model, ramp_frequency: nil, infer_hoo_for_non_assigned_objects: true, error_on_out_of_order: true)
|
502
|
+
runner.registerInfo("Created #{parametric_schedules.size} parametric schedules.")
|
503
|
+
|
504
|
+
# report final condition of model
|
505
|
+
hoo_summary_hash = hoo_summary(model, runner, standard)
|
506
|
+
if !hoo_summary_hash[:zero_hoo].empty?
|
507
|
+
runner.registerFinalCondition("Across the building the non-zero hours of operation range from #{hoo_summary_hash[:final_hoo_dur_range].min} hours to #{hoo_summary_hash[:final_hoo_dur_range].max} hours. Start of hours of operation range from #{hoo_summary_hash[:final_hoo_start_range].min} to #{hoo_summary_hash[:final_hoo_start_range].max}. One or more hours of operation schedules used contain a profile with 0 hours of operation.")
|
508
|
+
else
|
509
|
+
runner.registerFinalCondition("Across the building the hours of operation range from #{hoo_summary_hash[:final_hoo_dur_range].min} hours to #{hoo_summary_hash[:final_hoo_dur_range].max} hours. Start of hours of operation range from #{hoo_summary_hash[:final_hoo_start_range].min} to #{hoo_summary_hash[:final_hoo_start_range].max}.")
|
510
|
+
end
|
511
|
+
|
512
|
+
# get log messages (if debug in setup is true this will fail for error)
|
513
|
+
OsLib_HelperMethods.log_msgs
|
514
|
+
|
515
|
+
# TODO: - adding hours of operation to a schedule that doesn't have them to start with, like a sunday, can be problematic
|
516
|
+
# todo - start of day may not be reliable and there may not be formula inputs to show what occupied behavior is
|
517
|
+
# todo - in a situation like that it could be good to get formula from day that was non-zero to start with like weekday or saturday.
|
518
|
+
# todo - maybe standards can do something like this when making the formulas in the first place.
|
519
|
+
|
520
|
+
return true
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
524
|
+
# register the measure to be used by the application
|
525
|
+
ShiftHoursOfOperation.new.registerWithApplication
|