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,17 +9,17 @@
|
|
9
9
|
class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
10
10
|
# define the name that a user will see
|
11
11
|
def name
|
12
|
-
|
12
|
+
'Reduce Lighting Loads by Percentage'
|
13
13
|
end
|
14
14
|
|
15
15
|
# human readable description
|
16
16
|
def description
|
17
|
-
|
17
|
+
'The lighting system in this building uses more power per area than is required with the latest lighting technologies. Replace the lighting system with a newer, more efficient lighting technology. Newer technologies provide the same amount of light but use less energy in the process.'
|
18
18
|
end
|
19
19
|
|
20
20
|
# human readable description of modeling approach
|
21
21
|
def modeler_description
|
22
|
-
|
22
|
+
'This measure supports models which have a mixture of lighting assigned to spaces and space types. The lighting may be specified as individual luminaires, lighting equipment level, lighting power per area, or lighting power per person. Loop through all lights and luminaires in the specified space type or the entire building. Clone the definition if it is shared by other lights, rename and adjust the power based on the specified percentage. Link the new definition to the existing lights or luminaire instance. Adjust the power for lighting equipment assigned to a particular space but only if that space is part of the selected space type by looping through the objects first in space types and then in spaces, but again only for spaces that are in the specified space type (unless the entire building has been chosen). Material and installation cost increases will be applied to all costs related to both the definition and instance of the lighting object. If this measure includes baseline costs, then the material and installation costs of the lighting objects in the baseline model will be summed together and added as a capital cost on the building object.'
|
23
23
|
end
|
24
24
|
|
25
25
|
# define the arguments that the user will input
|
@@ -40,7 +40,7 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
40
40
|
# looping through sorted hash of model objects
|
41
41
|
space_type_args_hash.sort.map do |key, value|
|
42
42
|
# only include if space type is used in the model
|
43
|
-
|
43
|
+
unless value.spaces.empty?
|
44
44
|
space_type_handles << value.handle.to_s
|
45
45
|
space_type_display_names << key
|
46
46
|
end
|
@@ -52,20 +52,25 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
52
52
|
space_type_display_names << '*Entire Building*'
|
53
53
|
|
54
54
|
# make a choice argument for space type
|
55
|
-
space_type = OpenStudio::Measure::OSArgument.makeChoiceArgument('space_type', space_type_handles,
|
55
|
+
space_type = OpenStudio::Measure::OSArgument.makeChoiceArgument('space_type', space_type_handles,
|
56
|
+
space_type_display_names)
|
56
57
|
space_type.setDisplayName('Apply the Measure to a Specific Space Type or to the Entire Model')
|
57
58
|
space_type.setDefaultValue('*Entire Building*') # if no space type is chosen this will run on the entire building
|
58
59
|
args << space_type
|
59
60
|
|
60
61
|
# make an argument for reduction percentage
|
61
|
-
lighting_power_reduction_percent = OpenStudio::Measure::OSArgument.makeDoubleArgument(
|
62
|
+
lighting_power_reduction_percent = OpenStudio::Measure::OSArgument.makeDoubleArgument(
|
63
|
+
'lighting_power_reduction_percent', true
|
64
|
+
)
|
62
65
|
lighting_power_reduction_percent.setDisplayName('Lighting Power Reduction')
|
63
66
|
lighting_power_reduction_percent.setDefaultValue(30.0)
|
64
67
|
lighting_power_reduction_percent.setUnits('%')
|
65
68
|
args << lighting_power_reduction_percent
|
66
69
|
|
67
70
|
# make an argument for material and installation cost
|
68
|
-
material_and_installation_cost = OpenStudio::Measure::OSArgument.makeDoubleArgument(
|
71
|
+
material_and_installation_cost = OpenStudio::Measure::OSArgument.makeDoubleArgument(
|
72
|
+
'material_and_installation_cost', true
|
73
|
+
)
|
69
74
|
material_and_installation_cost.setDisplayName('Increase in Material and Installation Cost for Lighting per Floor Area')
|
70
75
|
material_and_installation_cost.setDefaultValue(0.0)
|
71
76
|
material_and_installation_cost.setUnits('%')
|
@@ -112,7 +117,7 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
112
117
|
om_frequency.setUnits('whole years')
|
113
118
|
args << om_frequency
|
114
119
|
|
115
|
-
|
120
|
+
args
|
116
121
|
end
|
117
122
|
|
118
123
|
# define what happens when the measure is run
|
@@ -120,9 +125,7 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
120
125
|
super(model, runner, user_arguments)
|
121
126
|
|
122
127
|
# use the built-in error checking
|
123
|
-
|
124
|
-
return false
|
125
|
-
end
|
128
|
+
return false unless runner.validateUserArguments(arguments(model), user_arguments)
|
126
129
|
|
127
130
|
# assign the user inputs to variables
|
128
131
|
object = runner.getOptionalWorkspaceObjectChoiceValue('space_type', user_arguments, model)
|
@@ -146,15 +149,13 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
146
149
|
runner.registerError("The selected space type with handle '#{handle}' was not found in the model. It may have been removed by another measure.")
|
147
150
|
end
|
148
151
|
return false
|
152
|
+
elsif !object.get.to_SpaceType.empty?
|
153
|
+
space_type = object.get.to_SpaceType.get
|
154
|
+
elsif !object.get.to_Building.empty?
|
155
|
+
apply_to_building = true
|
149
156
|
else
|
150
|
-
|
151
|
-
|
152
|
-
elsif !object.get.to_Building.empty?
|
153
|
-
apply_to_building = true
|
154
|
-
else
|
155
|
-
runner.registerError('Script Error - argument not showing up as space type or building.')
|
156
|
-
return false
|
157
|
-
end
|
157
|
+
runner.registerError('Script Error - argument not showing up as space type or building.')
|
158
|
+
return false
|
158
159
|
end
|
159
160
|
|
160
161
|
# check the lighting_power_reduction_percent and for reasonableness
|
@@ -197,24 +198,25 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
197
198
|
return false
|
198
199
|
end
|
199
200
|
|
200
|
-
if om_frequency < 1
|
201
|
-
runner.registerError('Choose an integer greater than 0 for O & M Frequency.')
|
202
|
-
end
|
201
|
+
runner.registerError('Choose an integer greater than 0 for O & M Frequency.') if om_frequency < 1
|
203
202
|
|
204
203
|
# helper to make numbers pretty (converts 4125001.25641 to 4,125,001.26 or 4,125,001). The definition be called through this measure.
|
205
204
|
def neat_numbers(number, roundto = 2) # round to 0 or 2)
|
206
|
-
if roundto == 2
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
205
|
+
number = if roundto == 2
|
206
|
+
format '%.2f', number
|
207
|
+
else
|
208
|
+
number.round
|
209
|
+
end
|
211
210
|
# regex to add commas
|
212
211
|
number.to_s.reverse.gsub(/([0-9]{3}(?=([0-9])))/, '\\1,').reverse
|
213
212
|
end
|
214
213
|
|
215
214
|
# helper to make it easier to do unit conversions on the fly. The definition be called through this measure.
|
216
215
|
def unit_helper(number, from_unit_string, to_unit_string)
|
217
|
-
converted_number = OpenStudio.convert(
|
216
|
+
converted_number = OpenStudio.convert(
|
217
|
+
OpenStudio::Quantity.new(number,
|
218
|
+
OpenStudio.createUnit(from_unit_string).get), OpenStudio.createUnit(to_unit_string).get
|
219
|
+
).get.value
|
218
220
|
end
|
219
221
|
|
220
222
|
# helper that loops through lifecycle costs getting total costs under "Construction" or "Salvage" category and add to counter if occurs during year 0
|
@@ -223,14 +225,12 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
223
225
|
objects.each do |object|
|
224
226
|
object_LCCs = object.lifeCycleCosts
|
225
227
|
object_LCCs.each do |object_LCC|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
end
|
230
|
-
end
|
228
|
+
next unless (object_LCC.category == 'Construction') || (object_LCC.category == 'Salvage')
|
229
|
+
|
230
|
+
counter += object_LCC.totalCost if object_LCC.yearsFromStart == 0
|
231
231
|
end
|
232
232
|
end
|
233
|
-
|
233
|
+
counter
|
234
234
|
end
|
235
235
|
|
236
236
|
# counter for demo cost of baseline objects
|
@@ -250,9 +250,13 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
250
250
|
# method should always return double but this is work around for when it is nan because of 0 floor area
|
251
251
|
if building.floorArea > 0.0
|
252
252
|
building_LPD = unit_helper(building.lightingPowerPerFloorArea, 'W/m^2', 'W/ft^2')
|
253
|
-
runner.registerInitialCondition("The model's initial building lighting power was #{neat_numbers(
|
253
|
+
runner.registerInitialCondition("The model's initial building lighting power was #{neat_numbers(
|
254
|
+
building_lighting_power, 0
|
255
|
+
)} watts, a lighting power density of #{neat_numbers(building_LPD)} w/ft^2.")
|
254
256
|
else
|
255
|
-
runner.registerInitialCondition("The model's initial building lighting power was #{neat_numbers(
|
257
|
+
runner.registerInitialCondition("The model's initial building lighting power was #{neat_numbers(
|
258
|
+
building_lighting_power, 0
|
259
|
+
)} watts. Building Area is not greater than 0 so an LPD can't be calculated.")
|
256
260
|
end
|
257
261
|
|
258
262
|
# get space types in model
|
@@ -269,24 +273,23 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
269
273
|
if demo_cost_initial_const == true
|
270
274
|
baseline_object_LCCs = baseline_object.lifeCycleCosts
|
271
275
|
baseline_object_LCCs.each do |baseline_object_LCC|
|
272
|
-
if baseline_object_LCC.category == 'Salvage'
|
273
|
-
counter += baseline_object_LCC.totalCost
|
274
|
-
end
|
276
|
+
counter += baseline_object_LCC.totalCost if baseline_object_LCC.category == 'Salvage'
|
275
277
|
end
|
276
278
|
end
|
277
|
-
|
279
|
+
counter
|
278
280
|
end
|
279
281
|
|
280
282
|
# def to alter performance and life cycle costs of objects
|
281
|
-
def alter_performance_and_lcc(object, lighting_power_reduction_percent, material_and_installation_cost,
|
283
|
+
def alter_performance_and_lcc(object, lighting_power_reduction_percent, material_and_installation_cost,
|
284
|
+
demolition_cost, om_cost, years_until_costs_start, expected_life, om_frequency, runner)
|
282
285
|
# edit clone based on percentage reduction
|
283
286
|
new_def = object
|
284
287
|
if !new_def.lightingLevel.empty?
|
285
|
-
new_lighting_level = new_def.setLightingLevel(new_def.lightingLevel.get - new_def.lightingLevel.get * lighting_power_reduction_percent * 0.01)
|
288
|
+
new_lighting_level = new_def.setLightingLevel(new_def.lightingLevel.get - (new_def.lightingLevel.get * lighting_power_reduction_percent * 0.01))
|
286
289
|
elsif !new_def.wattsperSpaceFloorArea.empty?
|
287
|
-
new_lighting_per_area = new_def.setWattsperSpaceFloorArea(new_def.wattsperSpaceFloorArea.get - new_def.wattsperSpaceFloorArea.get * lighting_power_reduction_percent * 0.01)
|
290
|
+
new_lighting_per_area = new_def.setWattsperSpaceFloorArea(new_def.wattsperSpaceFloorArea.get - (new_def.wattsperSpaceFloorArea.get * lighting_power_reduction_percent * 0.01))
|
288
291
|
elsif !new_def.wattsperPerson.empty?
|
289
|
-
new_lighting_per_person = new_def.setWattsperPerson(new_def.wattsperPerson.get - new_def.wattsperPerson.get * lighting_power_reduction_percent * 0.01)
|
292
|
+
new_lighting_per_person = new_def.setWattsperPerson(new_def.wattsperPerson.get - (new_def.wattsperPerson.get * lighting_power_reduction_percent * 0.01))
|
290
293
|
else
|
291
294
|
runner.registerWarning("'#{new_def.name}' is used by one or more instances and has no load values. Its performance was not altered.")
|
292
295
|
end
|
@@ -299,15 +302,15 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
299
302
|
else
|
300
303
|
new_def_LCCs.each do |new_def_LCC|
|
301
304
|
if new_def_LCC.category == 'Construction'
|
302
|
-
new_def_LCC.setCost(new_def_LCC.cost * (1 + material_and_installation_cost / 100))
|
305
|
+
new_def_LCC.setCost(new_def_LCC.cost * (1 + (material_and_installation_cost / 100)))
|
303
306
|
new_def_LCC.setYearsFromStart(years_until_costs_start) # just uses argument value, does not need existing value
|
304
307
|
new_def_LCC.setRepeatPeriodYears(expected_life) # just uses argument value, does not need existing value
|
305
308
|
elsif new_def_LCC.category == 'Salvage'
|
306
|
-
new_def_LCC.setCost(new_def_LCC.cost * (1 + demolition_cost / 100))
|
309
|
+
new_def_LCC.setCost(new_def_LCC.cost * (1 + (demolition_cost / 100)))
|
307
310
|
new_def_LCC.setYearsFromStart(years_until_costs_start + expected_life) # just uses argument value, does not need existing value
|
308
311
|
new_def_LCC.setRepeatPeriodYears(expected_life) # just uses argument value, does not need existing value
|
309
312
|
elsif new_def_LCC.category == 'Maintenance'
|
310
|
-
new_def_LCC.setCost(new_def_LCC.cost * (1 + om_cost / 100))
|
313
|
+
new_def_LCC.setCost(new_def_LCC.cost * (1 + (om_cost / 100)))
|
311
314
|
new_def_LCC.setRepeatPeriodYears(om_frequency) # just uses argument value, does not need existing value
|
312
315
|
end
|
313
316
|
|
@@ -326,11 +329,12 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
326
329
|
# loop through space types
|
327
330
|
space_types.each do |space_type|
|
328
331
|
next if space_type.spaces.size <= 0
|
332
|
+
|
329
333
|
space_type_lights = space_type.lights
|
330
334
|
space_type_lights.each do |space_type_light|
|
331
335
|
# clone def if it has not already been cloned
|
332
336
|
exist_def = space_type_light.lightsDefinition
|
333
|
-
if cloned_lights_defs.any? { |k,
|
337
|
+
if cloned_lights_defs.any? { |k, _v| k.to_s == exist_def.name.to_s }
|
334
338
|
new_def = cloned_lights_defs[exist_def.name.to_s]
|
335
339
|
else
|
336
340
|
# clone rename and add to hash
|
@@ -343,7 +347,8 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
343
347
|
demo_costs_of_baseline_objects += add_to_baseline_demo_cost_counter(exist_def, demo_cost_initial_const)
|
344
348
|
|
345
349
|
# call def to alter performance and life cycle costs
|
346
|
-
alter_performance_and_lcc(new_def, lighting_power_reduction_percent, material_and_installation_cost,
|
350
|
+
alter_performance_and_lcc(new_def, lighting_power_reduction_percent, material_and_installation_cost,
|
351
|
+
demolition_cost, om_cost, years_until_costs_start, expected_life, om_frequency, runner)
|
347
352
|
|
348
353
|
end
|
349
354
|
|
@@ -356,7 +361,7 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
356
361
|
space_type_luminaires.each do |space_type_luminaire|
|
357
362
|
# clone def if it has not already been cloned
|
358
363
|
exist_def = space_type_luminaire.luminaireDefinition
|
359
|
-
if cloned_luminaire_defs.any? { |k,
|
364
|
+
if cloned_luminaire_defs.any? { |k, _v| k.to_s == exist_def.name }
|
360
365
|
new_def = cloned_luminaire_defs[exist_def.name]
|
361
366
|
else
|
362
367
|
# clone rename and add to hash
|
@@ -369,7 +374,8 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
369
374
|
demo_costs_of_baseline_objects += add_to_baseline_demo_cost_counter(exist_def, demo_cost_initial_const)
|
370
375
|
|
371
376
|
# call def to alter performance and life cycle costs
|
372
|
-
alter_performance_and_lcc(new_def, lighting_power_reduction_percent, material_and_installation_cost,
|
377
|
+
alter_performance_and_lcc(new_def, lighting_power_reduction_percent, material_and_installation_cost,
|
378
|
+
demolition_cost, om_cost, years_until_costs_start, expected_life, om_frequency, runner)
|
373
379
|
|
374
380
|
end
|
375
381
|
|
@@ -385,10 +391,8 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
385
391
|
# get space types in model
|
386
392
|
if apply_to_building
|
387
393
|
spaces = model.getSpaces
|
388
|
-
|
389
|
-
|
390
|
-
spaces = space_type.spaces # only run on a single space type
|
391
|
-
end
|
394
|
+
elsif !space_type.spaces.empty?
|
395
|
+
spaces = space_type.spaces
|
392
396
|
end
|
393
397
|
|
394
398
|
spaces.each do |space|
|
@@ -396,7 +400,7 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
396
400
|
space_lights.each do |space_light|
|
397
401
|
# clone def if it has not already been cloned
|
398
402
|
exist_def = space_light.lightsDefinition
|
399
|
-
if cloned_lights_defs.any? { |k,
|
403
|
+
if cloned_lights_defs.any? { |k, _v| k.to_s == exist_def.name.to_s }
|
400
404
|
new_def = cloned_lights_defs[exist_def.name.to_s]
|
401
405
|
else
|
402
406
|
# clone rename and add to hash
|
@@ -409,7 +413,8 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
409
413
|
demo_costs_of_baseline_objects += add_to_baseline_demo_cost_counter(exist_def, demo_cost_initial_const)
|
410
414
|
|
411
415
|
# call def to alter performance and life cycle costs
|
412
|
-
alter_performance_and_lcc(new_def, lighting_power_reduction_percent, material_and_installation_cost,
|
416
|
+
alter_performance_and_lcc(new_def, lighting_power_reduction_percent, material_and_installation_cost,
|
417
|
+
demolition_cost, om_cost, years_until_costs_start, expected_life, om_frequency, runner)
|
413
418
|
|
414
419
|
end
|
415
420
|
|
@@ -422,7 +427,7 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
422
427
|
space_luminaires.each do |space_luminaire|
|
423
428
|
# clone def if it has not already been cloned
|
424
429
|
exist_def = space_luminaire.luminaireDefinition
|
425
|
-
if cloned_luminaire_defs.any? { |k,
|
430
|
+
if cloned_luminaire_defs.any? { |k, _v| k.to_s == exist_def.name }
|
426
431
|
new_def = cloned_luminaire_defs[exist_def.name]
|
427
432
|
else
|
428
433
|
# clone rename and add to hash
|
@@ -435,7 +440,8 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
435
440
|
demo_costs_of_baseline_objects += add_to_baseline_demo_cost_counter(exist_def, demo_cost_initial_const)
|
436
441
|
|
437
442
|
# call def to alter performance and life cycle costs
|
438
|
-
alter_performance_and_lcc(new_def, lighting_power_reduction_percent, material_and_installation_cost,
|
443
|
+
alter_performance_and_lcc(new_def, lighting_power_reduction_percent, material_and_installation_cost,
|
444
|
+
demolition_cost, om_cost, years_until_costs_start, expected_life, om_frequency, runner)
|
439
445
|
|
440
446
|
end
|
441
447
|
|
@@ -457,12 +463,11 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
457
463
|
if demo_cost_initial_const == true
|
458
464
|
building = model.getBuilding
|
459
465
|
lcc_baseline_demo = OpenStudio::Model::LifeCycleCost.createLifeCycleCost('LCC_baseline_demo', building, demo_costs_of_baseline_objects, 'CostPerEach', 'Salvage', 0, years_until_costs_start).get # using 0 for repeat period since one time cost.
|
460
|
-
runner.registerInfo("Adding one time cost of $#{neat_numbers(lcc_baseline_demo.totalCost,
|
466
|
+
runner.registerInfo("Adding one time cost of $#{neat_numbers(lcc_baseline_demo.totalCost,
|
467
|
+
0)} related to demolition of baseline objects.")
|
461
468
|
|
462
469
|
# if demo occurs on year 0 then add to initial capital cost counter
|
463
|
-
if lcc_baseline_demo.yearsFromStart == 0
|
464
|
-
yr0_capital_totalCosts += lcc_baseline_demo.totalCost
|
465
|
-
end
|
470
|
+
yr0_capital_totalCosts += lcc_baseline_demo.totalCost if lcc_baseline_demo.yearsFromStart == 0
|
466
471
|
end
|
467
472
|
|
468
473
|
# report final condition
|
@@ -472,12 +477,18 @@ class ReduceLightingLoadsByPercentage < OpenStudio::Measure::ModelMeasure
|
|
472
477
|
# method should always return double but this is work around for when it is nan because of 0 floor area
|
473
478
|
if building.floorArea > 0.0
|
474
479
|
final_building_LPD = unit_helper(final_building.lightingPowerPerFloorArea, 'W/m^2', 'W/ft^2')
|
475
|
-
runner.registerFinalCondition("The model's final final lighting power was #{neat_numbers(
|
480
|
+
runner.registerFinalCondition("The model's final final lighting power was #{neat_numbers(
|
481
|
+
final_building_lighting_power, 0
|
482
|
+
)} watts, a lighting power density of #{neat_numbers(final_building_LPD)} w/ft^2. Initial capital costs associated with the improvements are $#{neat_numbers(
|
483
|
+
yr0_capital_totalCosts, 0
|
484
|
+
)}.")
|
476
485
|
else
|
477
|
-
runner.registerFinalCondition("The model's final final lighting power was #{neat_numbers(
|
486
|
+
runner.registerFinalCondition("The model's final final lighting power was #{neat_numbers(
|
487
|
+
final_building_lighting_power, 0
|
488
|
+
)} wattsBuilding Area is not greater than 0 so an LPD can't be calculated.")
|
478
489
|
end
|
479
490
|
|
480
|
-
|
491
|
+
true
|
481
492
|
end
|
482
493
|
end
|
483
494
|
|
@@ -3,8 +3,8 @@
|
|
3
3
|
<schema_version>3.1</schema_version>
|
4
4
|
<name>reduce_lighting_loads_by_percentage</name>
|
5
5
|
<uid>791f3404-a28b-4a80-ba3f-e15b339e39ea</uid>
|
6
|
-
<version_id>
|
7
|
-
<version_modified>2025-
|
6
|
+
<version_id>0d447c49-6da8-40a0-ae1e-e40aa7d5844e</version_id>
|
7
|
+
<version_modified>2025-09-25T15:33:44Z</version_modified>
|
8
8
|
<xml_checksum>293730A7</xml_checksum>
|
9
9
|
<class_name>ReduceLightingLoadsByPercentage</class_name>
|
10
10
|
<display_name>Reduce Lighting Loads by Percentage</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>{99f185ba-0bd9-48d1-b66a-1cd70b749c8d}</default_value>
|
21
21
|
<choices>
|
22
22
|
<choice>
|
23
|
-
<value>{
|
23
|
+
<value>{99f185ba-0bd9-48d1-b66a-1cd70b749c8d}</value>
|
24
24
|
<display_name>*Entire Building*</display_name>
|
25
25
|
</choice>
|
26
26
|
</choices>
|
@@ -162,7 +162,7 @@
|
|
162
162
|
<filename>measure.rb</filename>
|
163
163
|
<filetype>rb</filetype>
|
164
164
|
<usage_type>script</usage_type>
|
165
|
-
<checksum>
|
165
|
+
<checksum>82DE91FC</checksum>
|
166
166
|
</file>
|
167
167
|
<file>
|
168
168
|
<filename>EC_QAQC.osm</filename>
|
@@ -186,7 +186,7 @@
|
|
186
186
|
<filename>ReduceLightingLoadsByPercentage_Test.rb</filename>
|
187
187
|
<filetype>rb</filetype>
|
188
188
|
<usage_type>test</usage_type>
|
189
|
-
<checksum>
|
189
|
+
<checksum>8EE6A0F2</checksum>
|
190
190
|
</file>
|
191
191
|
</files>
|
192
192
|
</measure>
|
@@ -9,7 +9,7 @@
|
|
9
9
|
class ReduceNightTimeElectricEquipmentLoads < OpenStudio::Measure::ModelMeasure
|
10
10
|
# define the name that a user will see
|
11
11
|
def name
|
12
|
-
|
12
|
+
'Reduce Night Time Electric Equipment Loads'
|
13
13
|
end
|
14
14
|
|
15
15
|
# define the arguments that the user will input
|
@@ -29,14 +29,15 @@ class ReduceNightTimeElectricEquipmentLoads < OpenStudio::Measure::ModelMeasure
|
|
29
29
|
|
30
30
|
# looping through sorted hash of load defs
|
31
31
|
elec_load_def_args_hash.sort.map do |key, value|
|
32
|
-
|
32
|
+
unless value.instances.empty?
|
33
33
|
elec_load_def_handles << value.handle.to_s
|
34
34
|
elec_load_def_display_names << key
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
# make an argument for electric equipment definition
|
39
|
-
elec_load_def = OpenStudio::Measure::OSArgument.makeChoiceArgument('elec_load_def', elec_load_def_handles,
|
39
|
+
elec_load_def = OpenStudio::Measure::OSArgument.makeChoiceArgument('elec_load_def', elec_load_def_handles,
|
40
|
+
elec_load_def_display_names)
|
40
41
|
elec_load_def.setDisplayName('Pick an Electric Equipment Definition(schedules using this will be altered)')
|
41
42
|
args << elec_load_def
|
42
43
|
|
@@ -130,7 +131,7 @@ class ReduceNightTimeElectricEquipmentLoads < 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 ReduceNightTimeElectricEquipmentLoads < 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
|
elec_load_def = runner.getOptionalWorkspaceObjectChoiceValue('elec_load_def', user_arguments, model)
|
@@ -169,13 +168,11 @@ class ReduceNightTimeElectricEquipmentLoads < OpenStudio::Measure::ModelMeasure
|
|
169
168
|
runner.registerError("An Electric Equipment Definition with handle '#{elec_load_def}' was not found in the model. It may have been removed by another measure.")
|
170
169
|
end
|
171
170
|
return false
|
171
|
+
elsif !elec_load_def.get.to_ElectricEquipmentDefinition.empty?
|
172
|
+
elec_load_def = elec_load_def.get.to_ElectricEquipmentDefinition.get
|
172
173
|
else
|
173
|
-
|
174
|
-
|
175
|
-
else
|
176
|
-
runner.registerError('Script Error - argument not showing up as electric equipment definition.')
|
177
|
-
return false
|
178
|
-
end
|
174
|
+
runner.registerError('Script Error - argument not showing up as electric equipment definition.')
|
175
|
+
return false
|
179
176
|
end
|
180
177
|
|
181
178
|
# check the fraction for reasonableness
|
@@ -294,17 +291,15 @@ class ReduceNightTimeElectricEquipmentLoads < 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 ReduceNightTimeElectricEquipmentLoads < OpenStudio::Measure::ModelMeasure
|
|
328
323
|
# get schedules for equipment instances that user the picked
|
329
324
|
equipment_instances.each do |equip|
|
330
325
|
next unless equip.electricEquipmentDefinition == elec_load_def
|
326
|
+
|
331
327
|
equipment_instances_using_def << equip
|
332
|
-
if
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
328
|
+
next if equip.schedule.empty?
|
329
|
+
|
330
|
+
equip_sch = equip.schedule.get
|
331
|
+
equip_schs[equip_sch.name.to_s] = equip_sch
|
332
|
+
equip_sch_names << equip_sch.name.to_s
|
337
333
|
end
|
338
334
|
|
339
335
|
# reporting initial condition of model
|
@@ -343,7 +339,9 @@ class ReduceNightTimeElectricEquipmentLoads < OpenStudio::Measure::ModelMeasure
|
|
343
339
|
# and reducing schedule fraction before and after the specified times
|
344
340
|
equip_sch_names.uniq.each do |equip_sch_name|
|
345
341
|
equip_sch = equip_schs[equip_sch_name]
|
346
|
-
if
|
342
|
+
if equip_sch.to_ScheduleRuleset.empty?
|
343
|
+
runner.registerWarning("Schedule '#{equip_sch_name}' isn't a ScheduleRuleset object and won't be altered by this measure.")
|
344
|
+
else
|
347
345
|
new_equip_sch = equip_sch.clone(model).to_ScheduleRuleset.get
|
348
346
|
new_equip_sch.setName("#{equip_sch_name} NightLoadControl")
|
349
347
|
reduced_equip_schs[equip_sch_name] = new_equip_sch
|
@@ -392,14 +390,16 @@ class ReduceNightTimeElectricEquipmentLoads < OpenStudio::Measure::ModelMeasure
|
|
392
390
|
if new_equip_sch.scheduleRules.empty?
|
393
391
|
runner.registerWarning("Schedule '#{new_equip_sch.name}' applies to all days. It has been treated as a Weekday schedule.")
|
394
392
|
end
|
395
|
-
reduce_schedule(new_equip_sch.defaultDaySchedule, wk_before_hour, wk_before_min, wk_before_value,
|
393
|
+
reduce_schedule(new_equip_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_equip_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 ReduceNightTimeElectricEquipmentLoads < 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_equip_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,12 +423,11 @@ class ReduceNightTimeElectricEquipmentLoads < OpenStudio::Measure::ModelMeasure
|
|
422
423
|
elsif sch_rule.applySaturday
|
423
424
|
runner.registerWarning("Rule '#{sch_rule.name}' for schedule '#{new_equip_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
|
-
else
|
430
|
-
runner.registerWarning("Schedule '#{equip_sch_name}' isn't a ScheduleRuleset object and won't be altered by this measure.")
|
431
431
|
end
|
432
432
|
end
|
433
433
|
|
@@ -445,9 +445,7 @@ class ReduceNightTimeElectricEquipmentLoads < OpenStudio::Measure::ModelMeasure
|
|
445
445
|
end
|
446
446
|
|
447
447
|
# na if no schedules to change
|
448
|
-
if equip_sch_names.uniq.empty?
|
449
|
-
runner.registerNotAsApplicable('There are no schedules to change.')
|
450
|
-
end
|
448
|
+
runner.registerNotAsApplicable('There are no schedules to change.') if equip_sch_names.uniq.empty?
|
451
449
|
|
452
450
|
measure_cost = 0
|
453
451
|
|
@@ -456,15 +454,19 @@ class ReduceNightTimeElectricEquipmentLoads < OpenStudio::Measure::ModelMeasure
|
|
456
454
|
if costs_requested == true
|
457
455
|
quantity = elec_load_def.quantity
|
458
456
|
# adding new cost items
|
459
|
-
lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_Mat - #{elec_load_def.name} night reduction",
|
460
|
-
|
457
|
+
lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_Mat - #{elec_load_def.name} night reduction",
|
458
|
+
building, material_cost * quantity, 'CostPerEach', 'Construction', expected_life, years_until_costs_start)
|
459
|
+
lcc_om = OpenStudio::Model::LifeCycleCost.createLifeCycleCost("LCC_OM - #{elec_load_def.name} night reduction",
|
460
|
+
building, om_cost * quantity, 'CostPerEach', 'Maintenance', om_frequency, 0)
|
461
461
|
measure_cost = material_cost * quantity
|
462
462
|
end
|
463
463
|
|
464
464
|
# reporting final condition of model
|
465
|
-
runner.registerFinalCondition("#{equip_sch_names.uniq.size} schedule(s) were edited. The cost for the measure is #{neat_numbers(
|
465
|
+
runner.registerFinalCondition("#{equip_sch_names.uniq.size} schedule(s) were edited. The cost for the measure is #{neat_numbers(
|
466
|
+
measure_cost, 0
|
467
|
+
)}.")
|
466
468
|
|
467
|
-
|
469
|
+
true
|
468
470
|
end
|
469
471
|
end
|
470
472
|
|
@@ -3,8 +3,8 @@
|
|
3
3
|
<schema_version>3.1</schema_version>
|
4
4
|
<name>reduce_night_time_electric_equipment_loads</name>
|
5
5
|
<uid>7bde0d05-3714-43e2-91b4-aa1e12e714bf</uid>
|
6
|
-
<version_id>
|
7
|
-
<version_modified>2025-
|
6
|
+
<version_id>ee1c5616-0abd-4c5e-9eb4-e539216911df</version_id>
|
7
|
+
<version_modified>2025-09-25T15:33:42Z</version_modified>
|
8
8
|
<xml_checksum>F4EB279D</xml_checksum>
|
9
9
|
<class_name>ReduceNightTimeElectricEquipmentLoads</class_name>
|
10
10
|
<display_name>Reduce Night Time Electric Equipment 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>E2A2BF6E</checksum>
|
228
228
|
</file>
|
229
229
|
<file>
|
230
230
|
<filename>EnvelopeAndLoadTestModel_01.osm</filename>
|
@@ -236,7 +236,7 @@
|
|
236
236
|
<filename>ReduceNightTimeElectricEquipmentLoads_Test.rb</filename>
|
237
237
|
<filetype>rb</filetype>
|
238
238
|
<usage_type>test</usage_type>
|
239
|
-
<checksum>
|
239
|
+
<checksum>12B0B531</checksum>
|
240
240
|
</file>
|
241
241
|
</files>
|
242
242
|
</measure>
|