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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.coverage +0 -0
  3. data/.github/workflows/test-with-openstudio.yml +109 -74
  4. data/.gitignore +21 -0
  5. data/.rubocop.yml +15 -2
  6. data/CHANGELOG.md +3 -0
  7. data/Gemfile +7 -8
  8. data/README.md +1 -0
  9. data/WORKFLOW_CHANGES.md +74 -0
  10. data/lib/measures/AddDaylightSensors/measure.rb +79 -79
  11. data/lib/measures/AddDaylightSensors/measure.xml +4 -4
  12. data/lib/measures/AddOverhangsByProjectionFactor/measure.rb +38 -41
  13. data/lib/measures/AddOverhangsByProjectionFactor/measure.xml +4 -4
  14. data/lib/measures/EnableDemandControlledVentilation/measure.rb +37 -40
  15. data/lib/measures/EnableDemandControlledVentilation/measure.xml +4 -4
  16. data/lib/measures/EnableEconomizerControl/measure.rb +36 -37
  17. data/lib/measures/EnableEconomizerControl/measure.xml +4 -4
  18. data/lib/measures/GLHEProExportLoadsforGroundHeatExchangerSizing/measure.rb +27 -41
  19. data/lib/measures/GLHEProExportLoadsforGroundHeatExchangerSizing/measure.xml +4 -4
  20. data/lib/measures/GLHEProGFunctionImport/measure.rb +11 -15
  21. data/lib/measures/GLHEProGFunctionImport/measure.xml +4 -4
  22. data/lib/measures/GLHEProSetupExportLoadsforGroundHeatExchangerSizing/measure.rb +5 -9
  23. data/lib/measures/GLHEProSetupExportLoadsforGroundHeatExchangerSizing/measure.xml +3 -3
  24. data/lib/measures/ImproveFanBeltEfficiency/measure.rb +78 -95
  25. data/lib/measures/ImproveFanBeltEfficiency/measure.xml +6 -6
  26. data/lib/measures/ImproveMotorEfficiency/measure.rb +75 -100
  27. data/lib/measures/ImproveMotorEfficiency/measure.xml +6 -6
  28. data/lib/measures/IncreaseInsulationRValueForExteriorWalls/measure.rb +137 -130
  29. data/lib/measures/IncreaseInsulationRValueForExteriorWalls/measure.xml +4 -4
  30. data/lib/measures/IncreaseInsulationRValueForExteriorWallsByPercentage/measure.rb +114 -115
  31. data/lib/measures/IncreaseInsulationRValueForExteriorWallsByPercentage/measure.xml +3 -3
  32. data/lib/measures/IncreaseInsulationRValueForRoofs/measure.rb +137 -130
  33. data/lib/measures/IncreaseInsulationRValueForRoofs/measure.xml +4 -4
  34. data/lib/measures/IncreaseInsulationRValueForRoofsByPercentage/measure.rb +114 -115
  35. data/lib/measures/IncreaseInsulationRValueForRoofsByPercentage/measure.xml +3 -3
  36. data/lib/measures/ReduceElectricEquipmentLoadsByPercentage/measure.rb +69 -63
  37. data/lib/measures/ReduceElectricEquipmentLoadsByPercentage/measure.xml +6 -6
  38. data/lib/measures/ReduceLightingLoadsByPercentage/measure.rb +77 -66
  39. data/lib/measures/ReduceLightingLoadsByPercentage/measure.xml +6 -6
  40. data/lib/measures/ReduceNightTimeElectricEquipmentLoads/measure.rb +45 -43
  41. data/lib/measures/ReduceNightTimeElectricEquipmentLoads/measure.xml +4 -4
  42. data/lib/measures/ReduceNightTimeLightingLoads/measure.rb +45 -43
  43. data/lib/measures/ReduceNightTimeLightingLoads/measure.xml +4 -4
  44. data/lib/measures/ReduceSpaceInfiltrationByPercentage/measure.rb +58 -52
  45. data/lib/measures/ReduceSpaceInfiltrationByPercentage/measure.xml +6 -6
  46. data/lib/measures/ReduceVentilationByPercentage/measure.rb +49 -46
  47. data/lib/measures/ReduceVentilationByPercentage/measure.xml +6 -6
  48. data/lib/measures/add_variable_speed_rtu_control_logic/measure.rb +31 -23
  49. data/lib/measures/add_variable_speed_rtu_control_logic/measure.xml +4 -4
  50. data/lib/measures/create_variable_speed_rtu/measure.rb +166 -174
  51. data/lib/measures/create_variable_speed_rtu/measure.xml +6 -6
  52. data/lib/measures/fan_assist_night_ventilation/measure.rb +33 -32
  53. data/lib/measures/fan_assist_night_ventilation/measure.xml +4 -4
  54. data/lib/measures/nze_hvac/measure.rb +72 -62
  55. data/lib/measures/nze_hvac/measure.xml +4 -4
  56. data/lib/measures/replace_water_heater_mixed_with_thermal_storage_chilled_water/measure.rb +16 -19
  57. data/lib/measures/replace_water_heater_mixed_with_thermal_storage_chilled_water/measure.xml +4 -4
  58. data/lib/measures/window_enhancement/LICENSE.md +14 -0
  59. data/lib/measures/window_enhancement/README.md +112 -0
  60. data/lib/measures/window_enhancement/docs/.gitkeep +0 -0
  61. data/lib/measures/window_enhancement/measure.py +386 -0
  62. data/lib/measures/window_enhancement/measure.xml +128 -0
  63. data/lib/measures/window_enhancement/resources/EC3_lookup.py +321 -0
  64. data/lib/measures/window_enhancement/resources/Test_API.py +32 -0
  65. data/lib/measures/window_enhancement/resources/__pycache__/EC3_lookup.cpython-39.pyc +0 -0
  66. data/lib/measures/window_enhancement/resources/__pycache__/Original_EC3_lookup.py +322 -0
  67. data/lib/measures/window_enhancement/resources/__pycache__/Test_API.cpython-39.pyc +0 -0
  68. data/lib/measures/window_enhancement/resources/calculate_perimeter.py +39 -0
  69. data/lib/measures/window_enhancement/test_output.log +39 -0
  70. data/lib/openstudio/ee_measures/version.rb +1 -1
  71. data/openstudio-ee.gemspec +10 -8
  72. data/test-workflow-locally.sh +152 -0
  73. metadata +64 -35
  74. 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
- return 'Reduce Night Time Lighting Loads'
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
- if !value.instances.empty?
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, lights_def_display_names)
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
- return args
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
- if !runner.validateUserArguments(arguments(model), user_arguments)
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
- if !lights_def.get.to_LightsDefinition.empty?
174
- lights_def = lights_def.get.to_LightsDefinition.get
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
- number = format '%.2f', number
305
- else
306
- number = number.round
307
- end
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 !light.schedule.empty?
333
- lights_sch = light.schedule.get
334
- lights_schs[lights_sch.name.to_s] = lights_sch
335
- lights_sch_names << lights_sch.name.to_s
336
- end
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 !lights_sch.to_ScheduleRuleset.empty?
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, wk_after_hour, wk_after_min, wk_after_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
- if apply_weekday
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, wk_after_min, wk_after_value)
402
- end
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, sat_after_min, sat_after_value)
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, sun_after_min, sun_after_value)
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", building, material_cost * quantity, 'CostPerEach', 'Construction', expected_life, years_until_costs_start)
461
- lcc_om = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_OM - #{lights_def.name} night reduction", building, om_cost * quantity, 'CostPerEach', 'Maintenance', om_frequency, 0)
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(measure_cost, 0)}.")
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
- return true
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>3058c4c5-c326-4929-90d7-57e2b4e4d988</version_id>
7
- <version_modified>2025-08-08T15:15:58Z</version_modified>
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>2641F702</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>926E0720</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
- return 'ReduceSpaceInfiltrationByPercentage'
22
+ 'ReduceSpaceInfiltrationByPercentage'
23
23
  end
24
24
 
25
25
  # human readable description
26
26
  def description
27
- return '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.'
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
- return '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.'
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
- if !value.spaces.empty?
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, space_type_display_names)
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('space_infiltration_reduction_percent', true)
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('wind_speed_squared_coefficient', true)
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('material_and_installation_cost', true)
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
- return args
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
- if !runner.validateUserArguments(arguments(model), user_arguments)
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', user_arguments)
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
- if !object.get.to_SpaceType.empty?
166
- space_type = object.get.to_SpaceType.get
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
- number = format '%.2f', number
199
- else
200
- number = number.round
201
- end
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 !space_infiltration_objects.empty?
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, wind_speed_coefficient, wind_speed_squared_coefficient, alter_coef, runner)
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
- if alter_coef
252
- instance.setConstantTermCoefficient(constant_coefficient)
253
- instance.setTemperatureTermCoefficient(temperature_coefficient)
254
- instance.setVelocityTermCoefficient(wind_speed_coefficient)
255
- instance.setVelocitySquaredTermCoefficient(wind_speed_squared_coefficient)
256
- end
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, temperature_coefficient, wind_speed_coefficient, wind_speed_squared_coefficient, alter_coef, runner)
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
- else
280
- if !space_type.spaces.empty?
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, temperature_coefficient, wind_speed_coefficient, wind_speed_squared_coefficient, alter_coef, runner)
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(affected_area_ip, 0)}(ft^2) at a total cost of $#{neat_numbers(final_cost, 0)}.")
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
- return true
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>f3a4891c-715f-4736-a1a5-3b1cbddbe343</version_id>
7
- <version_modified>2025-08-08T15:15:56Z</version_modified>
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>{e9970f4e-07dd-433b-adc1-e7dedcd762b3}</default_value>
20
+ <default_value>{873fd05a-3dff-4e05-80d4-59a5b492c31f}</default_value>
21
21
  <choices>
22
22
  <choice>
23
- <value>{e9970f4e-07dd-433b-adc1-e7dedcd762b3}</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>F7F6B0AE</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>9F83F933</checksum>
179
+ <checksum>E9669F9A</checksum>
180
180
  </file>
181
181
  </files>
182
182
  </measure>