openstudio-ee 0.12.3 → 0.12.4
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/.coverage +0 -0
- data/.github/workflows/test-with-openstudio.yml +109 -74
- data/.gitignore +21 -0
- data/.rubocop.yml +15 -2
- data/CHANGELOG.md +3 -0
- data/Gemfile +7 -8
- data/README.md +1 -0
- data/WORKFLOW_CHANGES.md +74 -0
- data/lib/measures/AddDaylightSensors/measure.rb +79 -79
- data/lib/measures/AddDaylightSensors/measure.xml +4 -4
- data/lib/measures/AddOverhangsByProjectionFactor/measure.rb +38 -41
- data/lib/measures/AddOverhangsByProjectionFactor/measure.xml +4 -4
- data/lib/measures/EnableDemandControlledVentilation/measure.rb +37 -40
- data/lib/measures/EnableDemandControlledVentilation/measure.xml +4 -4
- data/lib/measures/EnableEconomizerControl/measure.rb +36 -37
- data/lib/measures/EnableEconomizerControl/measure.xml +4 -4
- data/lib/measures/GLHEProExportLoadsforGroundHeatExchangerSizing/measure.rb +27 -41
- data/lib/measures/GLHEProExportLoadsforGroundHeatExchangerSizing/measure.xml +4 -4
- data/lib/measures/GLHEProGFunctionImport/measure.rb +11 -15
- data/lib/measures/GLHEProGFunctionImport/measure.xml +4 -4
- data/lib/measures/GLHEProSetupExportLoadsforGroundHeatExchangerSizing/measure.rb +5 -9
- data/lib/measures/GLHEProSetupExportLoadsforGroundHeatExchangerSizing/measure.xml +3 -3
- data/lib/measures/ImproveFanBeltEfficiency/measure.rb +78 -95
- data/lib/measures/ImproveFanBeltEfficiency/measure.xml +6 -6
- data/lib/measures/ImproveMotorEfficiency/measure.rb +75 -100
- data/lib/measures/ImproveMotorEfficiency/measure.xml +6 -6
- data/lib/measures/IncreaseInsulationRValueForExteriorWalls/measure.rb +137 -130
- data/lib/measures/IncreaseInsulationRValueForExteriorWalls/measure.xml +4 -4
- data/lib/measures/IncreaseInsulationRValueForExteriorWallsByPercentage/measure.rb +114 -115
- data/lib/measures/IncreaseInsulationRValueForExteriorWallsByPercentage/measure.xml +3 -3
- data/lib/measures/IncreaseInsulationRValueForRoofs/measure.rb +137 -130
- data/lib/measures/IncreaseInsulationRValueForRoofs/measure.xml +4 -4
- data/lib/measures/IncreaseInsulationRValueForRoofsByPercentage/measure.rb +114 -115
- data/lib/measures/IncreaseInsulationRValueForRoofsByPercentage/measure.xml +3 -3
- data/lib/measures/ReduceElectricEquipmentLoadsByPercentage/measure.rb +69 -63
- data/lib/measures/ReduceElectricEquipmentLoadsByPercentage/measure.xml +6 -6
- data/lib/measures/ReduceLightingLoadsByPercentage/measure.rb +77 -66
- data/lib/measures/ReduceLightingLoadsByPercentage/measure.xml +6 -6
- data/lib/measures/ReduceNightTimeElectricEquipmentLoads/measure.rb +45 -43
- data/lib/measures/ReduceNightTimeElectricEquipmentLoads/measure.xml +4 -4
- data/lib/measures/ReduceNightTimeLightingLoads/measure.rb +45 -43
- data/lib/measures/ReduceNightTimeLightingLoads/measure.xml +4 -4
- data/lib/measures/ReduceSpaceInfiltrationByPercentage/measure.rb +58 -52
- data/lib/measures/ReduceSpaceInfiltrationByPercentage/measure.xml +6 -6
- data/lib/measures/ReduceVentilationByPercentage/measure.rb +49 -46
- data/lib/measures/ReduceVentilationByPercentage/measure.xml +6 -6
- data/lib/measures/add_variable_speed_rtu_control_logic/measure.rb +31 -23
- data/lib/measures/add_variable_speed_rtu_control_logic/measure.xml +4 -4
- data/lib/measures/create_variable_speed_rtu/measure.rb +166 -174
- data/lib/measures/create_variable_speed_rtu/measure.xml +6 -6
- data/lib/measures/fan_assist_night_ventilation/measure.rb +33 -32
- data/lib/measures/fan_assist_night_ventilation/measure.xml +4 -4
- data/lib/measures/nze_hvac/measure.rb +72 -62
- data/lib/measures/nze_hvac/measure.xml +4 -4
- data/lib/measures/replace_water_heater_mixed_with_thermal_storage_chilled_water/measure.rb +16 -19
- data/lib/measures/replace_water_heater_mixed_with_thermal_storage_chilled_water/measure.xml +4 -4
- data/lib/measures/window_enhancement/LICENSE.md +14 -0
- data/lib/measures/window_enhancement/README.md +112 -0
- data/lib/measures/window_enhancement/docs/.gitkeep +0 -0
- data/lib/measures/window_enhancement/measure.py +386 -0
- data/lib/measures/window_enhancement/measure.xml +128 -0
- data/lib/measures/window_enhancement/resources/EC3_lookup.py +321 -0
- data/lib/measures/window_enhancement/resources/Test_API.py +32 -0
- data/lib/measures/window_enhancement/resources/__pycache__/EC3_lookup.cpython-39.pyc +0 -0
- data/lib/measures/window_enhancement/resources/__pycache__/Original_EC3_lookup.py +322 -0
- data/lib/measures/window_enhancement/resources/__pycache__/Test_API.cpython-39.pyc +0 -0
- data/lib/measures/window_enhancement/resources/calculate_perimeter.py +39 -0
- data/lib/measures/window_enhancement/test_output.log +39 -0
- data/lib/openstudio/ee_measures/version.rb +1 -1
- data/openstudio-ee.gemspec +10 -8
- data/test-workflow-locally.sh +152 -0
- metadata +64 -35
- data/Jenkinsfile +0 -11
@@ -9,7 +9,7 @@
|
|
9
9
|
class ReduceNightTimeLightingLoads < OpenStudio::Measure::ModelMeasure
|
10
10
|
# define the name that a user will see
|
11
11
|
def name
|
12
|
-
|
12
|
+
'Reduce Night Time Lighting Loads'
|
13
13
|
end
|
14
14
|
|
15
15
|
# define the arguments that the user will input
|
@@ -29,14 +29,15 @@ class ReduceNightTimeLightingLoads < OpenStudio::Measure::ModelMeasure
|
|
29
29
|
|
30
30
|
# looping through sorted hash of load defs
|
31
31
|
light_def_args_hash.sort.map do |key, value|
|
32
|
-
|
32
|
+
unless value.instances.empty?
|
33
33
|
lights_def_handles << value.handle.to_s
|
34
34
|
lights_def_display_names << key
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
# make an argument for lights definition
|
39
|
-
lights_def = OpenStudio::Measure::OSArgument.makeChoiceArgument('lights_def', lights_def_handles,
|
39
|
+
lights_def = OpenStudio::Measure::OSArgument.makeChoiceArgument('lights_def', lights_def_handles,
|
40
|
+
lights_def_display_names)
|
40
41
|
lights_def.setDisplayName('Pick a Lighting Definition From the Model (schedules using this will be altered)')
|
41
42
|
args << lights_def
|
42
43
|
|
@@ -130,7 +131,7 @@ class ReduceNightTimeLightingLoads < OpenStudio::Measure::ModelMeasure
|
|
130
131
|
om_frequency.setDefaultValue(1)
|
131
132
|
args << om_frequency
|
132
133
|
|
133
|
-
|
134
|
+
args
|
134
135
|
end
|
135
136
|
|
136
137
|
# define what happens when the measure is run
|
@@ -138,9 +139,7 @@ class ReduceNightTimeLightingLoads < OpenStudio::Measure::ModelMeasure
|
|
138
139
|
super(model, runner, user_arguments)
|
139
140
|
|
140
141
|
# use the built-in error checking
|
141
|
-
|
142
|
-
return false
|
143
|
-
end
|
142
|
+
return false unless runner.validateUserArguments(arguments(model), user_arguments)
|
144
143
|
|
145
144
|
# assign the user inputs to variables
|
146
145
|
lights_def = runner.getOptionalWorkspaceObjectChoiceValue('lights_def', user_arguments, model)
|
@@ -169,13 +168,11 @@ class ReduceNightTimeLightingLoads < OpenStudio::Measure::ModelMeasure
|
|
169
168
|
runner.registerError("A Lighting Definition with handle '#{lights_def}' was not found in the model. It may have been removed by another measure.")
|
170
169
|
end
|
171
170
|
return false
|
171
|
+
elsif !lights_def.get.to_LightsDefinition.empty?
|
172
|
+
lights_def = lights_def.get.to_LightsDefinition.get
|
172
173
|
else
|
173
|
-
|
174
|
-
|
175
|
-
else
|
176
|
-
runner.registerError('Script Error - argument not showing up as lights definition.')
|
177
|
-
return false
|
178
|
-
end
|
174
|
+
runner.registerError('Script Error - argument not showing up as lights definition.')
|
175
|
+
return false
|
179
176
|
end
|
180
177
|
|
181
178
|
# check the fraction for reasonableness
|
@@ -294,17 +291,15 @@ class ReduceNightTimeLightingLoads < OpenStudio::Measure::ModelMeasure
|
|
294
291
|
if (expected_life < 1) && (expected_life > 100)
|
295
292
|
runner.registerError('Choose an integer greater than 0 and less than or equal to 100 for Expected Life.')
|
296
293
|
end
|
297
|
-
if om_frequency < 1
|
298
|
-
runner.registerError('Choose an integer greater than 0 for O & M Frequency.')
|
299
|
-
end
|
294
|
+
runner.registerError('Choose an integer greater than 0 for O & M Frequency.') if om_frequency < 1
|
300
295
|
|
301
296
|
# short def to make numbers pretty (converts 4125001.25641 to 4,125,001.26 or 4,125,001). The definition be called through this measure
|
302
297
|
def neat_numbers(number, roundto = 2) # round to 0 or 2)
|
303
|
-
if roundto == 2
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
298
|
+
number = if roundto == 2
|
299
|
+
format '%.2f', number
|
300
|
+
else
|
301
|
+
number.round
|
302
|
+
end
|
308
303
|
# regex to add commas
|
309
304
|
number.to_s.reverse.gsub(/([0-9]{3}(?=([0-9])))/, '\\1,').reverse
|
310
305
|
end
|
@@ -328,12 +323,13 @@ class ReduceNightTimeLightingLoads < OpenStudio::Measure::ModelMeasure
|
|
328
323
|
# get schedules for lights instances that user the picked
|
329
324
|
lighting_instances.each do |light|
|
330
325
|
next unless light.lightsDefinition == lights_def
|
326
|
+
|
331
327
|
lighting_instances_using_def << light
|
332
|
-
if
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
328
|
+
next if light.schedule.empty?
|
329
|
+
|
330
|
+
lights_sch = light.schedule.get
|
331
|
+
lights_schs[lights_sch.name.to_s] = lights_sch
|
332
|
+
lights_sch_names << lights_sch.name.to_s
|
337
333
|
end
|
338
334
|
|
339
335
|
# reporting initial condition of model
|
@@ -343,7 +339,9 @@ class ReduceNightTimeLightingLoads < OpenStudio::Measure::ModelMeasure
|
|
343
339
|
# and reducing schedule fraction before and after the specified times
|
344
340
|
lights_sch_names.uniq.each do |lights_sch_name|
|
345
341
|
lights_sch = lights_schs[lights_sch_name]
|
346
|
-
if
|
342
|
+
if lights_sch.to_ScheduleRuleset.empty?
|
343
|
+
runner.registerWarning("Schedule '#{lights_sch_name}' isn't a ScheduleRuleset object and won't be altered by this measure.")
|
344
|
+
else
|
347
345
|
new_lights_sch = lights_sch.clone(model).to_ScheduleRuleset.get
|
348
346
|
new_lights_sch.setName("#{lights_sch_name} NightLightingControl")
|
349
347
|
reduced_lights_schs[lights_sch_name] = new_lights_sch
|
@@ -392,14 +390,16 @@ class ReduceNightTimeLightingLoads < OpenStudio::Measure::ModelMeasure
|
|
392
390
|
if new_lights_sch.scheduleRules.empty?
|
393
391
|
runner.registerWarning("Schedule '#{new_lights_sch.name}' applies to all days. It has been treated as a Weekday schedule.")
|
394
392
|
end
|
395
|
-
reduce_schedule(new_lights_sch.defaultDaySchedule, wk_before_hour, wk_before_min, wk_before_value,
|
393
|
+
reduce_schedule(new_lights_sch.defaultDaySchedule, wk_before_hour, wk_before_min, wk_before_value,
|
394
|
+
wk_after_hour, wk_after_min, wk_after_value)
|
396
395
|
|
397
396
|
# reduce weekdays
|
398
397
|
new_lights_sch.scheduleRules.each do |sch_rule|
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
398
|
+
next unless apply_weekday
|
399
|
+
|
400
|
+
if sch_rule.applyMonday || sch_rule.applyTuesday || sch_rule.applyWednesday || sch_rule.applyThursday || sch_rule.applyFriday
|
401
|
+
reduce_schedule(sch_rule.daySchedule, wk_before_hour, wk_before_min, wk_before_value, wk_after_hour,
|
402
|
+
wk_after_min, wk_after_value)
|
403
403
|
end
|
404
404
|
end
|
405
405
|
|
@@ -409,7 +409,8 @@ class ReduceNightTimeLightingLoads < OpenStudio::Measure::ModelMeasure
|
|
409
409
|
if sch_rule.applyMonday || sch_rule.applyTuesday || sch_rule.applyWednesday || sch_rule.applyThursday || sch_rule.applyFriday
|
410
410
|
runner.registerWarning("Rule '#{sch_rule.name}' for schedule '#{new_lights_sch.name}' applies to both Saturdays and Weekdays. It has been treated as a Weekday schedule.")
|
411
411
|
else
|
412
|
-
reduce_schedule(sch_rule.daySchedule, sat_before_hour, sat_before_min, sat_before_value, sat_after_hour,
|
412
|
+
reduce_schedule(sch_rule.daySchedule, sat_before_hour, sat_before_min, sat_before_value, sat_after_hour,
|
413
|
+
sat_after_min, sat_after_value)
|
413
414
|
end
|
414
415
|
end
|
415
416
|
end
|
@@ -422,13 +423,12 @@ class ReduceNightTimeLightingLoads < OpenStudio::Measure::ModelMeasure
|
|
422
423
|
elsif sch_rule.applySaturday
|
423
424
|
runner.registerWarning("Rule '#{sch_rule.name}' for schedule '#{new_lights_sch.name}' applies to both Saturdays and Sundays. It has been treated as a Saturday schedule.")
|
424
425
|
else
|
425
|
-
reduce_schedule(sch_rule.daySchedule, sun_before_hour, sun_before_min, sun_before_value, sun_after_hour,
|
426
|
+
reduce_schedule(sch_rule.daySchedule, sun_before_hour, sun_before_min, sun_before_value, sun_after_hour,
|
427
|
+
sun_after_min, sun_after_value)
|
426
428
|
end
|
427
429
|
end
|
428
430
|
end
|
429
431
|
|
430
|
-
else
|
431
|
-
runner.registerWarning("Schedule '#{lights_sch_name}' isn't a ScheduleRuleset object and won't be altered by this measure.")
|
432
432
|
end
|
433
433
|
end
|
434
434
|
|
@@ -446,9 +446,7 @@ class ReduceNightTimeLightingLoads < OpenStudio::Measure::ModelMeasure
|
|
446
446
|
end
|
447
447
|
|
448
448
|
# na if no schedules to change
|
449
|
-
if lights_sch_names.uniq.empty?
|
450
|
-
runner.registerNotAsApplicable('There are no schedules to change.')
|
451
|
-
end
|
449
|
+
runner.registerNotAsApplicable('There are no schedules to change.') if lights_sch_names.uniq.empty?
|
452
450
|
|
453
451
|
measure_cost = 0
|
454
452
|
|
@@ -457,15 +455,19 @@ class ReduceNightTimeLightingLoads < OpenStudio::Measure::ModelMeasure
|
|
457
455
|
if costs_requested == true
|
458
456
|
quantity = lights_def.quantity
|
459
457
|
# adding new cost items
|
460
|
-
lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_Mat - #{lights_def.name} night reduction",
|
461
|
-
|
458
|
+
lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_Mat - #{lights_def.name} night reduction",
|
459
|
+
building, material_cost * quantity, 'CostPerEach', 'Construction', expected_life, years_until_costs_start)
|
460
|
+
lcc_om = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_OM - #{lights_def.name} night reduction",
|
461
|
+
building, om_cost * quantity, 'CostPerEach', 'Maintenance', om_frequency, 0)
|
462
462
|
measure_cost = material_cost * quantity
|
463
463
|
end
|
464
464
|
|
465
465
|
# reporting final condition of model
|
466
|
-
runner.registerFinalCondition("#{lights_sch_names.uniq.size} schedule(s) were edited. The cost for the measure is #{neat_numbers(
|
466
|
+
runner.registerFinalCondition("#{lights_sch_names.uniq.size} schedule(s) were edited. The cost for the measure is #{neat_numbers(
|
467
|
+
measure_cost, 0
|
468
|
+
)}.")
|
467
469
|
|
468
|
-
|
470
|
+
true
|
469
471
|
end
|
470
472
|
end
|
471
473
|
|
@@ -3,8 +3,8 @@
|
|
3
3
|
<schema_version>3.1</schema_version>
|
4
4
|
<name>reduce_night_time_lighting_loads</name>
|
5
5
|
<uid>acce8fde-a5d7-4c27-af89-28327132bafa</uid>
|
6
|
-
<version_id>
|
7
|
-
<version_modified>2025-
|
6
|
+
<version_id>64d7f496-fa8e-409f-9e9a-9a69c3a0022f</version_id>
|
7
|
+
<version_modified>2025-09-25T15:33:44Z</version_modified>
|
8
8
|
<xml_checksum>0AC58119</xml_checksum>
|
9
9
|
<class_name>ReduceNightTimeLightingLoads</class_name>
|
10
10
|
<display_name>Reduce Night Time Lighting Loads</display_name>
|
@@ -224,7 +224,7 @@
|
|
224
224
|
<filename>measure.rb</filename>
|
225
225
|
<filetype>rb</filetype>
|
226
226
|
<usage_type>script</usage_type>
|
227
|
-
<checksum>
|
227
|
+
<checksum>A5407321</checksum>
|
228
228
|
</file>
|
229
229
|
<file>
|
230
230
|
<filename>EnvelopeAndLoadTestModel_01.osm</filename>
|
@@ -236,7 +236,7 @@
|
|
236
236
|
<filename>ReduceNightTimeLightingLoads_Test.rb</filename>
|
237
237
|
<filetype>rb</filetype>
|
238
238
|
<usage_type>test</usage_type>
|
239
|
-
<checksum>
|
239
|
+
<checksum>4CB3E9CB</checksum>
|
240
240
|
</file>
|
241
241
|
</files>
|
242
242
|
</measure>
|
@@ -19,17 +19,17 @@ class ReduceSpaceInfiltrationByPercentage < OpenStudio::Measure::ModelMeasure
|
|
19
19
|
# define the name that a user will see, this method may be deprecated as
|
20
20
|
# the display name in PAT comes from the name field in measure.xml
|
21
21
|
def name
|
22
|
-
|
22
|
+
'ReduceSpaceInfiltrationByPercentage'
|
23
23
|
end
|
24
24
|
|
25
25
|
# human readable description
|
26
26
|
def description
|
27
|
-
|
27
|
+
'This measure will reduce space infiltration rates by the requested percentage. A cost per square foot of building area can be added to the model.'
|
28
28
|
end
|
29
29
|
|
30
30
|
# human readable description of modeling approach
|
31
31
|
def modeler_description
|
32
|
-
|
32
|
+
'This can be run across a space type or the entire building. Costs will be associated with the building. If infiltration objects are removed at a later date, the costs will remain.'
|
33
33
|
end
|
34
34
|
|
35
35
|
# define the arguments that the user will input
|
@@ -50,7 +50,7 @@ class ReduceSpaceInfiltrationByPercentage < OpenStudio::Measure::ModelMeasure
|
|
50
50
|
# looping through sorted hash of model objects
|
51
51
|
space_type_args_hash.sort.map do |key, value|
|
52
52
|
# only include if space type is used in the model
|
53
|
-
|
53
|
+
unless value.spaces.empty?
|
54
54
|
space_type_handles << value.handle.to_s
|
55
55
|
space_type_display_names << key
|
56
56
|
end
|
@@ -62,13 +62,16 @@ class ReduceSpaceInfiltrationByPercentage < OpenStudio::Measure::ModelMeasure
|
|
62
62
|
space_type_display_names << '*Entire Building*'
|
63
63
|
|
64
64
|
# make a choice argument for space type
|
65
|
-
space_type = OpenStudio::Measure::OSArgument.makeChoiceArgument('space_type', space_type_handles,
|
65
|
+
space_type = OpenStudio::Measure::OSArgument.makeChoiceArgument('space_type', space_type_handles,
|
66
|
+
space_type_display_names)
|
66
67
|
space_type.setDisplayName('Apply the Measure to a Specific Space Type or to the Entire Model.')
|
67
68
|
space_type.setDefaultValue('*Entire Building*') # if no space type is chosen this will run on the entire building
|
68
69
|
args << space_type
|
69
70
|
|
70
71
|
# make an argument for reduction percentage
|
71
|
-
space_infiltration_reduction_percent = OpenStudio::Measure::OSArgument.makeDoubleArgument(
|
72
|
+
space_infiltration_reduction_percent = OpenStudio::Measure::OSArgument.makeDoubleArgument(
|
73
|
+
'space_infiltration_reduction_percent', true
|
74
|
+
)
|
72
75
|
space_infiltration_reduction_percent.setDisplayName('Space Infiltration Power Reduction')
|
73
76
|
space_infiltration_reduction_percent.setDefaultValue(30.0)
|
74
77
|
space_infiltration_reduction_percent.setUnits('%')
|
@@ -93,7 +96,9 @@ class ReduceSpaceInfiltrationByPercentage < OpenStudio::Measure::ModelMeasure
|
|
93
96
|
args << wind_speed_coefficient
|
94
97
|
|
95
98
|
# make an argument for wind_speed_squared_coefficient
|
96
|
-
wind_speed_squared_coefficient = OpenStudio::Measure::OSArgument.makeDoubleArgument(
|
99
|
+
wind_speed_squared_coefficient = OpenStudio::Measure::OSArgument.makeDoubleArgument(
|
100
|
+
'wind_speed_squared_coefficient', true
|
101
|
+
)
|
97
102
|
wind_speed_squared_coefficient.setDisplayName('Wind Speed Squared Coefficient')
|
98
103
|
wind_speed_squared_coefficient.setDefaultValue(0.0)
|
99
104
|
args << wind_speed_squared_coefficient
|
@@ -106,7 +111,9 @@ class ReduceSpaceInfiltrationByPercentage < OpenStudio::Measure::ModelMeasure
|
|
106
111
|
args << alter_coef
|
107
112
|
|
108
113
|
# make an argument for material and installation cost
|
109
|
-
material_and_installation_cost = OpenStudio::Measure::OSArgument.makeDoubleArgument(
|
114
|
+
material_and_installation_cost = OpenStudio::Measure::OSArgument.makeDoubleArgument(
|
115
|
+
'material_and_installation_cost', true
|
116
|
+
)
|
110
117
|
material_and_installation_cost.setDisplayName('Increase in Material and Installation Costs for Building per Affected Floor Area')
|
111
118
|
material_and_installation_cost.setDefaultValue(0.0)
|
112
119
|
material_and_installation_cost.setUnits('$/ft^2')
|
@@ -126,7 +133,7 @@ class ReduceSpaceInfiltrationByPercentage < OpenStudio::Measure::ModelMeasure
|
|
126
133
|
om_frequency.setUnits('whole years')
|
127
134
|
args << om_frequency
|
128
135
|
|
129
|
-
|
136
|
+
args
|
130
137
|
end
|
131
138
|
|
132
139
|
# define what happens when the measure is run
|
@@ -134,13 +141,12 @@ class ReduceSpaceInfiltrationByPercentage < OpenStudio::Measure::ModelMeasure
|
|
134
141
|
super(model, runner, user_arguments)
|
135
142
|
|
136
143
|
# use the built-in error checking
|
137
|
-
|
138
|
-
return false
|
139
|
-
end
|
144
|
+
return false unless runner.validateUserArguments(arguments(model), user_arguments)
|
140
145
|
|
141
146
|
# assign the user inputs to variables
|
142
147
|
object = runner.getOptionalWorkspaceObjectChoiceValue('space_type', user_arguments, model)
|
143
|
-
space_infiltration_reduction_percent = runner.getDoubleArgumentValue('space_infiltration_reduction_percent',
|
148
|
+
space_infiltration_reduction_percent = runner.getDoubleArgumentValue('space_infiltration_reduction_percent',
|
149
|
+
user_arguments)
|
144
150
|
constant_coefficient = runner.getDoubleArgumentValue('constant_coefficient', user_arguments)
|
145
151
|
temperature_coefficient = runner.getDoubleArgumentValue('temperature_coefficient', user_arguments)
|
146
152
|
wind_speed_coefficient = runner.getDoubleArgumentValue('wind_speed_coefficient', user_arguments)
|
@@ -161,15 +167,13 @@ class ReduceSpaceInfiltrationByPercentage < OpenStudio::Measure::ModelMeasure
|
|
161
167
|
runner.registerError("The selected space type with handle '#{handle}' was not found in the model. It may have been removed by another measure.")
|
162
168
|
end
|
163
169
|
return false
|
170
|
+
elsif !object.get.to_SpaceType.empty?
|
171
|
+
space_type = object.get.to_SpaceType.get
|
172
|
+
elsif !object.get.to_Building.empty?
|
173
|
+
apply_to_building = true
|
164
174
|
else
|
165
|
-
|
166
|
-
|
167
|
-
elsif !object.get.to_Building.empty?
|
168
|
-
apply_to_building = true
|
169
|
-
else
|
170
|
-
runner.registerError('Script Error - argument not showing up as space type or building.')
|
171
|
-
return false
|
172
|
-
end
|
175
|
+
runner.registerError('Script Error - argument not showing up as space type or building.')
|
176
|
+
return false
|
173
177
|
end
|
174
178
|
|
175
179
|
# check the space_infiltration_reduction_percent and for reasonableness
|
@@ -188,17 +192,15 @@ class ReduceSpaceInfiltrationByPercentage < OpenStudio::Measure::ModelMeasure
|
|
188
192
|
|
189
193
|
# TODO: - currently not checking for negative $/ft^2 for material_and_installation_cost and om_cost, confirm if E+ will allow negative cost
|
190
194
|
|
191
|
-
if om_frequency < 1
|
192
|
-
runner.registerError('Choose an integer greater than 0 for O & M Frequency.')
|
193
|
-
end
|
195
|
+
runner.registerError('Choose an integer greater than 0 for O & M Frequency.') if om_frequency < 1
|
194
196
|
|
195
197
|
# helper to make numbers pretty (converts 4125001.25641 to 4,125,001.26 or 4,125,001). The definition be called through this measure.
|
196
198
|
def neat_numbers(number, roundto = 2) # round to 0 or 2)
|
197
|
-
if roundto == 2
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
199
|
+
number = if roundto == 2
|
200
|
+
format '%.2f', number
|
201
|
+
else
|
202
|
+
number.round
|
203
|
+
end
|
202
204
|
# regex to add commas
|
203
205
|
number.to_s.reverse.gsub(/([0-9]{3}(?=([0-9])))/, '\\1,').reverse
|
204
206
|
end
|
@@ -212,10 +214,10 @@ class ReduceSpaceInfiltrationByPercentage < OpenStudio::Measure::ModelMeasure
|
|
212
214
|
affected_area_si = 0
|
213
215
|
|
214
216
|
# reporting initial condition of model
|
215
|
-
if
|
216
|
-
runner.registerInitialCondition("The initial model contained #{space_infiltration_objects.size} space infiltration objects.")
|
217
|
-
else
|
217
|
+
if space_infiltration_objects.empty?
|
218
218
|
runner.registerInitialCondition('The initial model did not contain any space infiltration objects.')
|
219
|
+
else
|
220
|
+
runner.registerInitialCondition("The initial model contained #{space_infiltration_objects.size} space infiltration objects.")
|
219
221
|
end
|
220
222
|
|
221
223
|
# get space types in model
|
@@ -230,39 +232,42 @@ class ReduceSpaceInfiltrationByPercentage < OpenStudio::Measure::ModelMeasure
|
|
230
232
|
end
|
231
233
|
|
232
234
|
# def to alter performance and life cycle costs of objects
|
233
|
-
def alter_performance(object, space_infiltration_reduction_percent, constant_coefficient, temperature_coefficient,
|
235
|
+
def alter_performance(object, space_infiltration_reduction_percent, constant_coefficient, temperature_coefficient,
|
236
|
+
wind_speed_coefficient, wind_speed_squared_coefficient, alter_coef, runner)
|
234
237
|
# edit instance based on percentage reduction
|
235
238
|
instance = object
|
236
239
|
if !instance.designFlowRate.empty?
|
237
|
-
new_infiltration_design_flow_rate = instance.setDesignFlowRate(instance.designFlowRate.get - instance.designFlowRate.get * space_infiltration_reduction_percent * 0.01)
|
240
|
+
new_infiltration_design_flow_rate = instance.setDesignFlowRate(instance.designFlowRate.get - (instance.designFlowRate.get * space_infiltration_reduction_percent * 0.01))
|
238
241
|
elsif !instance.flowperSpaceFloorArea.empty?
|
239
|
-
new_infiltration_flow_floor_area = instance.setFlowperSpaceFloorArea(instance.flowperSpaceFloorArea.get - instance.flowperSpaceFloorArea.get * space_infiltration_reduction_percent * 0.01)
|
242
|
+
new_infiltration_flow_floor_area = instance.setFlowperSpaceFloorArea(instance.flowperSpaceFloorArea.get - (instance.flowperSpaceFloorArea.get * space_infiltration_reduction_percent * 0.01))
|
240
243
|
elsif !instance.flowperExteriorSurfaceArea.empty?
|
241
|
-
new_infiltration_flow_ext_area = instance.setFlowperExteriorSurfaceArea(instance.flowperExteriorSurfaceArea.get - instance.flowperExteriorSurfaceArea.get * space_infiltration_reduction_percent * 0.01)
|
244
|
+
new_infiltration_flow_ext_area = instance.setFlowperExteriorSurfaceArea(instance.flowperExteriorSurfaceArea.get - (instance.flowperExteriorSurfaceArea.get * space_infiltration_reduction_percent * 0.01))
|
242
245
|
elsif !instance.flowperExteriorWallArea.empty?
|
243
|
-
new_infiltration_flow_ext_area = instance.setFlowperExteriorWallArea(instance.flowperExteriorWallArea.get - instance.flowperExteriorWallArea.get * space_infiltration_reduction_percent * 0.01)
|
246
|
+
new_infiltration_flow_ext_area = instance.setFlowperExteriorWallArea(instance.flowperExteriorWallArea.get - (instance.flowperExteriorWallArea.get * space_infiltration_reduction_percent * 0.01))
|
244
247
|
elsif !instance.airChangesperHour.empty?
|
245
|
-
new_infiltration_ach = instance.setAirChangesperHour(instance.airChangesperHour.get - instance.airChangesperHour.get * space_infiltration_reduction_percent * 0.01)
|
248
|
+
new_infiltration_ach = instance.setAirChangesperHour(instance.airChangesperHour.get - (instance.airChangesperHour.get * space_infiltration_reduction_percent * 0.01))
|
246
249
|
else
|
247
250
|
runner.registerWarning("'#{instance.name}' is used by one or more instances and has no load values.")
|
248
251
|
end
|
249
252
|
|
250
253
|
# only alter coefficients if requested
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
254
|
+
return unless alter_coef
|
255
|
+
|
256
|
+
instance.setConstantTermCoefficient(constant_coefficient)
|
257
|
+
instance.setTemperatureTermCoefficient(temperature_coefficient)
|
258
|
+
instance.setVelocityTermCoefficient(wind_speed_coefficient)
|
259
|
+
instance.setVelocitySquaredTermCoefficient(wind_speed_squared_coefficient)
|
257
260
|
end
|
258
261
|
|
259
262
|
# loop through space types
|
260
263
|
space_types.each do |space_type|
|
261
264
|
next if space_type.spaces.size <= 0
|
265
|
+
|
262
266
|
space_type_infiltration_objects = space_type.spaceInfiltrationDesignFlowRates
|
263
267
|
space_type_infiltration_objects.each do |space_type_infiltration_object|
|
264
268
|
# call def to alter performance and life cycle costs
|
265
|
-
alter_performance(space_type_infiltration_object, space_infiltration_reduction_percent, constant_coefficient,
|
269
|
+
alter_performance(space_type_infiltration_object, space_infiltration_reduction_percent, constant_coefficient,
|
270
|
+
temperature_coefficient, wind_speed_coefficient, wind_speed_squared_coefficient, alter_coef, runner)
|
266
271
|
|
267
272
|
# rename
|
268
273
|
updated_instance_name = space_type_infiltration_object.setName("#{space_type_infiltration_object.name} #{space_infiltration_reduction_percent} percent reduction")
|
@@ -276,17 +281,16 @@ class ReduceSpaceInfiltrationByPercentage < OpenStudio::Measure::ModelMeasure
|
|
276
281
|
# get space types in model
|
277
282
|
if apply_to_building
|
278
283
|
spaces = model.getSpaces
|
279
|
-
|
280
|
-
|
281
|
-
spaces = space_type.spaces # only run on a single space type
|
282
|
-
end
|
284
|
+
elsif !space_type.spaces.empty?
|
285
|
+
spaces = space_type.spaces
|
283
286
|
end
|
284
287
|
|
285
288
|
spaces.each do |space|
|
286
289
|
space_infiltration_objects = space.spaceInfiltrationDesignFlowRates
|
287
290
|
space_infiltration_objects.each do |space_infiltration_object|
|
288
291
|
# call def to alter performance and life cycle costs
|
289
|
-
alter_performance(space_infiltration_object, space_infiltration_reduction_percent, constant_coefficient,
|
292
|
+
alter_performance(space_infiltration_object, space_infiltration_reduction_percent, constant_coefficient,
|
293
|
+
temperature_coefficient, wind_speed_coefficient, wind_speed_squared_coefficient, alter_coef, runner)
|
290
294
|
|
291
295
|
# rename
|
292
296
|
updated_instance_name = space_infiltration_object.setName("#{space_infiltration_object.name} #{space_infiltration_reduction_percent} percent reduction")
|
@@ -311,9 +315,11 @@ class ReduceSpaceInfiltrationByPercentage < OpenStudio::Measure::ModelMeasure
|
|
311
315
|
end
|
312
316
|
|
313
317
|
# report final condition
|
314
|
-
runner.registerFinalCondition("#{altered_instances} space infiltration objects in the model were altered affecting #{neat_numbers(
|
318
|
+
runner.registerFinalCondition("#{altered_instances} space infiltration objects in the model were altered affecting #{neat_numbers(
|
319
|
+
affected_area_ip, 0
|
320
|
+
)}(ft^2) at a total cost of $#{neat_numbers(final_cost, 0)}.")
|
315
321
|
|
316
|
-
|
322
|
+
true
|
317
323
|
end
|
318
324
|
end
|
319
325
|
|
@@ -3,8 +3,8 @@
|
|
3
3
|
<schema_version>3.1</schema_version>
|
4
4
|
<name>reduce_space_infiltration_by_percentage</name>
|
5
5
|
<uid>6e9de4b1-aa97-4010-80c8-529e53ffe943</uid>
|
6
|
-
<version_id>
|
7
|
-
<version_modified>2025-
|
6
|
+
<version_id>b1bd09e1-4ba1-4759-b642-65dfa8bcf283</version_id>
|
7
|
+
<version_modified>2025-09-25T15:33:42Z</version_modified>
|
8
8
|
<xml_checksum>EACB548E</xml_checksum>
|
9
9
|
<class_name>ReduceSpaceInfiltrationByPercentage</class_name>
|
10
10
|
<display_name>ReduceSpaceInfiltrationByPercentage</display_name>
|
@@ -17,10 +17,10 @@
|
|
17
17
|
<type>Choice</type>
|
18
18
|
<required>true</required>
|
19
19
|
<model_dependent>false</model_dependent>
|
20
|
-
<default_value>{
|
20
|
+
<default_value>{873fd05a-3dff-4e05-80d4-59a5b492c31f}</default_value>
|
21
21
|
<choices>
|
22
22
|
<choice>
|
23
|
-
<value>{
|
23
|
+
<value>{873fd05a-3dff-4e05-80d4-59a5b492c31f}</value>
|
24
24
|
<display_name>*Entire Building*</display_name>
|
25
25
|
</choice>
|
26
26
|
</choices>
|
@@ -158,7 +158,7 @@
|
|
158
158
|
<filename>measure.rb</filename>
|
159
159
|
<filetype>rb</filetype>
|
160
160
|
<usage_type>script</usage_type>
|
161
|
-
<checksum>
|
161
|
+
<checksum>155D496B</checksum>
|
162
162
|
</file>
|
163
163
|
<file>
|
164
164
|
<filename>EnvelopeAndLoadTestModel_01.osm</filename>
|
@@ -176,7 +176,7 @@
|
|
176
176
|
<filename>ReduceSpaceInfiltrationByPercentage_Test.rb</filename>
|
177
177
|
<filetype>rb</filetype>
|
178
178
|
<usage_type>test</usage_type>
|
179
|
-
<checksum>
|
179
|
+
<checksum>E9669F9A</checksum>
|
180
180
|
</file>
|
181
181
|
</files>
|
182
182
|
</measure>
|