openstudio-geb 0.0.2 → 0.0.3r
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/.gitignore +3 -1
- data/lib/measures/AdjustThermostatSetpointsByDegreesForPeakHours/measure.rb +1 -1
- data/lib/measures/add_chilled_water_storage_tank/measure.rb +167 -36
- data/lib/measures/add_chilled_water_storage_tank/tests/restaurant.osm +12189 -0
- data/lib/measures/average_ventilation_for_peak_hours/measure.rb +22 -11
- data/lib/measures/average_ventilation_for_peak_hours/tests/LargeOffice-90.1-2013-ASHRAE 169-2013-5A.osm +21863 -0
- data/lib/measures/reduce_epd_by_percentage_for_peak_hours/measure.rb +94 -95
- data/lib/openstudio/geb/version.rb +1 -1
- metadata +7 -5
- data/lib/measures/average_ventilation_for_peak_hours/tests/example_model.osm +0 -8077
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95736fe58727e0f60da222a3f643c02dc5e5465dc77b5e6513012a59949d9d85
|
4
|
+
data.tar.gz: 55105af8ce0bf75e1005123a36f77e61268136554663d6b476091e1995396bae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63d3ff9b2cc8415a52ba1906a61146ed28ba6a977da91393e84fa0ed7e6845240beea11c03d20483b86f92b56b4f779fff42a08f093544bc59e43dcce0453605
|
7
|
+
data.tar.gz: 02f4cfd1f7b5e87d3c14c142a15cf370aa19793a3f280fd772b39a972c844680d817fb40123caf7c8f914a4686c85a14de4375078de197c77196b79a619ef390
|
data/.gitignore
CHANGED
@@ -673,7 +673,7 @@ class AdjustThermostatSetpointsByDegreesForPeakHours < OpenStudio::Measure::Mode
|
|
673
673
|
elsif vec_time[i]>time_begin && vec_time[i]<=time_end && count==1
|
674
674
|
sch_day.addValue(vec_time[i], vec_value[i])
|
675
675
|
elsif vec_time[i]>time_end && count == 1
|
676
|
-
sch_day.addValue(time_end, target_temp_si)
|
676
|
+
sch_day.addValue(time_end, target_temp_si.value)
|
677
677
|
sch_day.addValue(vec_time[i], vec_value[i])
|
678
678
|
count = 2
|
679
679
|
else
|
@@ -49,9 +49,9 @@ class AddChilledWaterStorageTank < OpenStudio::Measure::ModelMeasure
|
|
49
49
|
loop_choices << loop.name.to_s
|
50
50
|
end
|
51
51
|
end
|
52
|
-
|
52
|
+
loop_choices << ""
|
53
53
|
# Make choice argument for primary loop selection
|
54
|
-
selected_primary_loop_name = OpenStudio::Measure::OSArgument.makeChoiceArgument('selected_primary_loop_name', loop_choices,
|
54
|
+
selected_primary_loop_name = OpenStudio::Measure::OSArgument.makeChoiceArgument('selected_primary_loop_name', loop_choices, false)
|
55
55
|
selected_primary_loop_name.setDisplayName('Select Primary Loop:')
|
56
56
|
selected_primary_loop_name.setDescription('This is the primary cooling loop on which the chilled water tank will be added.')
|
57
57
|
pri_loop_name = nil
|
@@ -62,6 +62,7 @@ class AddChilledWaterStorageTank < OpenStudio::Measure::ModelMeasure
|
|
62
62
|
selected_primary_loop_name.setDefaultValue(pri_loop_name)
|
63
63
|
else
|
64
64
|
selected_primary_loop_name.setDescription('Error: No Cooling Loop Found')
|
65
|
+
selected_primary_loop_name.setDefaultValue("")
|
65
66
|
end
|
66
67
|
args << selected_primary_loop_name
|
67
68
|
|
@@ -156,12 +157,13 @@ class AddChilledWaterStorageTank < OpenStudio::Measure::ModelMeasure
|
|
156
157
|
args << wknds
|
157
158
|
|
158
159
|
# Output path, for sizing run
|
159
|
-
run_output_path = OpenStudio::Measure::OSArgument.makePathArgument('run_output_path', true, "")
|
160
|
+
run_output_path = OpenStudio::Measure::OSArgument.makePathArgument('run_output_path', true, "", false)
|
160
161
|
run_output_path.setDisplayName('Output path for tank sizing run (if tank volume is not provided)')
|
162
|
+
run_output_path.setDefaultValue(".")
|
161
163
|
args << run_output_path
|
162
164
|
|
163
165
|
# epw file path, for sizing run
|
164
|
-
epw_path = OpenStudio::Measure::OSArgument.makePathArgument('epw_path', true, "")
|
166
|
+
epw_path = OpenStudio::Measure::OSArgument.makePathArgument('epw_path', true, "", false)
|
165
167
|
epw_path.setDisplayName('epw file path for tank sizing run (if tank volume is not provided)')
|
166
168
|
args << epw_path
|
167
169
|
|
@@ -187,6 +189,36 @@ class AddChilledWaterStorageTank < OpenStudio::Measure::ModelMeasure
|
|
187
189
|
# assign the user inputs to variables
|
188
190
|
objective = runner.getStringArgumentValue('objective', user_arguments)
|
189
191
|
selected_primary_loop_name = runner.getStringArgumentValue('selected_primary_loop_name', user_arguments)
|
192
|
+
# if user_arguments['selected_primary_loop_name'].hasValue
|
193
|
+
# selected_primary_loop_name = runner.getStringArgumentValue('selected_primary_loop_name', user_arguments)
|
194
|
+
if !selected_primary_loop_name.empty?
|
195
|
+
# get the primary cooling loop
|
196
|
+
selected_primary_loop = model.getModelObjectByName(selected_primary_loop_name)
|
197
|
+
if selected_primary_loop.is_initialized
|
198
|
+
selected_primary_loop = selected_primary_loop.get.to_PlantLoop.get
|
199
|
+
else
|
200
|
+
# The provided value is not a plant loop in the model
|
201
|
+
runner.registerError("The provided primary loop name doesn't exist in the model.")
|
202
|
+
return false
|
203
|
+
end
|
204
|
+
else
|
205
|
+
loop_choices = []
|
206
|
+
model.getPlantLoops.each do |loop|
|
207
|
+
if loop.sizingPlant.loopType.to_s == 'Cooling'
|
208
|
+
loop_choices << loop.name.to_s
|
209
|
+
end
|
210
|
+
end
|
211
|
+
if loop_choices.empty?
|
212
|
+
# No cooling loop; the measure is not applicable
|
213
|
+
runner.registerAsNotApplicable("No cooling loop in the model. The measure is not applicable.")
|
214
|
+
return true
|
215
|
+
else
|
216
|
+
# There is cooling loop in the model but user didn't specify one,
|
217
|
+
# and the cooling loop name does not include 'chilled water loop'
|
218
|
+
runner.registerError("Please select a primary loop name to run the measure. The available cooling loop(s) in the model is #{loop_choices.join(', ')}")
|
219
|
+
return false
|
220
|
+
end
|
221
|
+
end
|
190
222
|
primary_loop_sp = runner.getDoubleArgumentValue('primary_loop_sp', user_arguments)
|
191
223
|
secondary_loop_sp = runner.getDoubleArgumentValue('secondary_loop_sp', user_arguments)
|
192
224
|
tank_charge_sp = runner.getDoubleArgumentValue('tank_charge_sp', user_arguments)
|
@@ -199,6 +231,7 @@ class AddChilledWaterStorageTank < OpenStudio::Measure::ModelMeasure
|
|
199
231
|
charge_end = runner.getStringArgumentValue('charge_end', user_arguments)
|
200
232
|
wknds = runner.getBoolArgumentValue('wknds', user_arguments)
|
201
233
|
|
234
|
+
|
202
235
|
# check time format
|
203
236
|
begin
|
204
237
|
discharge_start = Time.strptime(discharge_start, '%H:%M')
|
@@ -293,14 +326,7 @@ class AddChilledWaterStorageTank < OpenStudio::Measure::ModelMeasure
|
|
293
326
|
return false
|
294
327
|
end
|
295
328
|
|
296
|
-
|
297
|
-
selected_primary_loop = model.getModelObjectByName(selected_primary_loop_name)
|
298
|
-
if selected_primary_loop.is_initialized
|
299
|
-
selected_primary_loop = selected_primary_loop.get.to_PlantLoop.get
|
300
|
-
else
|
301
|
-
runner.registerError("Error: No Primary Cooling Loop Found. ")
|
302
|
-
return false
|
303
|
-
end
|
329
|
+
|
304
330
|
# report initial condition of model
|
305
331
|
runner.registerInitialCondition("Original primary chilled water loop: #{selected_primary_loop.name}.")
|
306
332
|
|
@@ -312,17 +338,112 @@ class AddChilledWaterStorageTank < OpenStudio::Measure::ModelMeasure
|
|
312
338
|
primary_delta_t = selected_primary_loop.sizingPlant.loopDesignTemperatureDifference
|
313
339
|
end
|
314
340
|
|
341
|
+
# get the condenser water loop
|
342
|
+
cw_loop = nil
|
343
|
+
model.getPlantLoops.each do |loop|
|
344
|
+
if loop.sizingPlant.loopType.to_s.downcase == 'condenser'
|
345
|
+
cw_loop = loop if cw_loop.nil?
|
346
|
+
# confirm if this condenser loop contains demand component of chiller that is in the selected_primary_loop
|
347
|
+
common_comps = cw_loop.demandComponents & selected_primary_loop.supplyComponents
|
348
|
+
chiller_in_both_loops = false
|
349
|
+
common_comps.each do |comp|
|
350
|
+
chiller_in_both_loops = true if comp.to_ChillerElectricEIR.is_initialized || comp.to_ChillerAbsorption.is_initialized || comp.to_ChillerAbsorptionIndirect.is_initialized
|
351
|
+
end
|
352
|
+
cw_loop = nil unless chiller_in_both_loops
|
353
|
+
end
|
354
|
+
end
|
355
|
+
# not necessarily can find a cw_loop as the existing primary chiller might be air cooled.
|
356
|
+
|
357
|
+
def hardsize_cooling_tower_two_speed(tower)
|
358
|
+
# implement the applySizingValues function for CoolingTowerTwoSpeed here since it's not yet implemented in OS standards
|
359
|
+
rated_water_flow_rate = tower.autosizedDesignWaterFlowRate
|
360
|
+
if rated_water_flow_rate.is_initialized
|
361
|
+
tower.setDesignWaterFlowRate(rated_water_flow_rate.get)
|
362
|
+
end
|
363
|
+
|
364
|
+
high_fan_speed_fan_power = tower.autosizedHighFanSpeedFanPower
|
365
|
+
if high_fan_speed_fan_power.is_initialized
|
366
|
+
tower.setHighFanSpeedFanPower(high_fan_speed_fan_power.get)
|
367
|
+
end
|
368
|
+
|
369
|
+
high_fan_speed_air_flow_rate = tower.autosizedHighFanSpeedAirFlowRate
|
370
|
+
if high_fan_speed_air_flow_rate.is_initialized
|
371
|
+
tower.setHighFanSpeedAirFlowRate(high_fan_speed_air_flow_rate.get)
|
372
|
+
end
|
373
|
+
|
374
|
+
high_fan_speed_u_factor_times_area_value = tower.autosizedHighFanSpeedUFactorTimesAreaValue
|
375
|
+
if high_fan_speed_u_factor_times_area_value.is_initialized
|
376
|
+
tower.setHighFanSpeedUFactorTimesAreaValue(high_fan_speed_u_factor_times_area_value.get)
|
377
|
+
end
|
378
|
+
|
379
|
+
low_fan_speed_air_flow_rate = tower.autosizedLowFanSpeedAirFlowRate
|
380
|
+
if low_fan_speed_air_flow_rate.is_initialized
|
381
|
+
tower.setLowFanSpeedAirFlowRate(low_fan_speed_air_flow_rate.get)
|
382
|
+
end
|
383
|
+
|
384
|
+
low_fan_speed_fan_power = tower.autosizedLowFanSpeedFanPower
|
385
|
+
if low_fan_speed_fan_power.is_initialized
|
386
|
+
tower.setLowFanSpeedFanPower(low_fan_speed_fan_power.get)
|
387
|
+
end
|
388
|
+
|
389
|
+
low_fan_speed_u_factor_times_area_value = tower.autosizedLowFanSpeedUFactorTimesAreaValue
|
390
|
+
if low_fan_speed_u_factor_times_area_value.is_initialized
|
391
|
+
tower.setLowFanSpeedUFactorTimesAreaValue(low_fan_speed_u_factor_times_area_value.get)
|
392
|
+
end
|
393
|
+
|
394
|
+
free_convection_regime_air_flow_rate = tower.autosizedFreeConvectionRegimeAirFlowRate
|
395
|
+
if free_convection_regime_air_flow_rate.is_initialized
|
396
|
+
tower.setFreeConvectionRegimeAirFlowRate(free_convection_regime_air_flow_rate.get)
|
397
|
+
end
|
398
|
+
|
399
|
+
free_convection_regime_u_factor_times_area_value = tower.autosizedFreeConvectionRegimeUFactorTimesAreaValue
|
400
|
+
if free_convection_regime_u_factor_times_area_value.is_initialized
|
401
|
+
tower.setFreeConvectionRegimeUFactorTimesAreaValue(free_convection_regime_u_factor_times_area_value.get)
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
315
405
|
# if user provides this input, if not, do autosizing
|
316
406
|
if user_arguments['tank_vol'].hasValue
|
317
407
|
tank_vol = runner.getDoubleArgumentValue('tank_vol', user_arguments)
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
408
|
+
if cw_loop
|
409
|
+
# autosize cooling tower in the condenser loop to avoid invalid hard-sized parameters
|
410
|
+
cw_loop.supplyComponents.each do |comp|
|
411
|
+
if comp.to_CoolingTowerSingleSpeed.is_initialized
|
412
|
+
cooling_tower = comp.to_CoolingTowerSingleSpeed.get
|
413
|
+
cooling_tower.autosizeDesignWaterFlowRate
|
414
|
+
cooling_tower.autosizeFanPoweratDesignAirFlowRate
|
415
|
+
cooling_tower.autosizeDesignAirFlowRate
|
416
|
+
cooling_tower.autosizeUFactorTimesAreaValueatDesignAirFlowRate
|
417
|
+
cooling_tower.autosizeAirFlowRateinFreeConvectionRegime
|
418
|
+
cooling_tower.autosizeUFactorTimesAreaValueatFreeConvectionAirFlowRate
|
419
|
+
runner.registerInfo("CoolingTowerSingleSpeed #{cooling_tower.name} has been set to autosize.")
|
420
|
+
elsif comp.to_CoolingTowerTwoSpeed.is_initialized
|
421
|
+
cooling_tower = comp.to_CoolingTowerTwoSpeed.get
|
422
|
+
cooling_tower.autosizeDesignWaterFlowRate
|
423
|
+
cooling_tower.autosizeHighFanSpeedFanPower
|
424
|
+
cooling_tower.autosizeHighFanSpeedAirFlowRate
|
425
|
+
cooling_tower.autosizeHighFanSpeedUFactorTimesAreaValue
|
426
|
+
cooling_tower.autosizeLowFanSpeedAirFlowRate
|
427
|
+
cooling_tower.autosizeLowFanSpeedFanPower
|
428
|
+
cooling_tower.autosizeLowFanSpeedUFactorTimesAreaValue
|
429
|
+
cooling_tower.autosizeFreeConvectionRegimeAirFlowRate
|
430
|
+
cooling_tower.autosizeFreeConvectionRegimeUFactorTimesAreaValue
|
431
|
+
runner.registerInfo("CoolingTowerTwoSpeed #{cooling_tower.name} has been set to autosize.")
|
432
|
+
elsif comp.to_CoolingTowerVariableSpeed.is_initialized
|
433
|
+
cooling_tower = comp.to_CoolingTowerVariableSpeed.get
|
434
|
+
cooling_tower.autosize
|
435
|
+
runner.registerInfo("CoolingTowerVariableSpeed #{cooling_tower.name} has been set to autosize.")
|
436
|
+
end
|
437
|
+
end
|
322
438
|
end
|
439
|
+
else
|
440
|
+
# unless user_arguments['run_output_path'].hasValue
|
441
|
+
# runner.registerError("Need to provide run output path for sizing run of tank volume. ")
|
442
|
+
# return false
|
443
|
+
# end
|
323
444
|
run_output_path = runner.getPathArgumentValue('run_output_path', user_arguments)
|
324
445
|
Dir.mkdir(run_output_path.to_s) unless File.exists?(run_output_path.to_s)
|
325
|
-
sizing_output_path = File.join(run_output_path.to_s, 'sizing_run')
|
446
|
+
sizing_output_path = File.expand_path(File.join(run_output_path.to_s, 'sizing_run'))
|
326
447
|
Dir.mkdir(sizing_output_path.to_s) unless File.exists?(sizing_output_path.to_s)
|
327
448
|
|
328
449
|
# Change the simulation to only run the sizing days
|
@@ -351,11 +472,18 @@ class AddChilledWaterStorageTank < OpenStudio::Measure::ModelMeasure
|
|
351
472
|
File.open(osw_path, 'w') do |f|
|
352
473
|
f << JSON.pretty_generate(osw)
|
353
474
|
end
|
475
|
+
model.resetSqlFile
|
354
476
|
run_osw(osw_path)
|
355
477
|
sleep(1)
|
356
|
-
|
357
|
-
|
358
|
-
|
478
|
+
sql_path = OpenStudio::Path.new(File.join(sizing_output_path.to_s, "run", "eplusout.sql"))
|
479
|
+
if OpenStudio.exists(sql_path)
|
480
|
+
sql = OpenStudio::SqlFile.new(sql_path)
|
481
|
+
unless sql.connectionOpen
|
482
|
+
runner.registerError("The sizing run failed without valid a sql file. Look at the eplusout.err file in #{File.dirname(sql_path.to_s)} to see the cause.")
|
483
|
+
return false
|
484
|
+
end
|
485
|
+
# Attach the sql file from the run to the model
|
486
|
+
model.setSqlFile(sql)
|
359
487
|
end
|
360
488
|
|
361
489
|
total_cooling_cap = 0 # initial
|
@@ -368,6 +496,24 @@ class AddChilledWaterStorageTank < OpenStudio::Measure::ModelMeasure
|
|
368
496
|
total_cooling_cap += comp.to_ChillerAbsorptionIndirect.get.autosizedNominalCapacity.get
|
369
497
|
end
|
370
498
|
end
|
499
|
+
if cw_loop
|
500
|
+
# hard size cooling tower in the condenser loop
|
501
|
+
cw_loop.supplyComponents.each do |comp|
|
502
|
+
if comp.to_CoolingTowerSingleSpeed.is_initialized
|
503
|
+
cooling_tower = comp.to_CoolingTowerSingleSpeed.get
|
504
|
+
cooling_tower.applySizingValues
|
505
|
+
runner.registerInfo("Autosized parameters from the sizing run have been set to CoolingTowerSingleSpeed #{cooling_tower.name}")
|
506
|
+
elsif comp.to_CoolingTowerTwoSpeed.is_initialized
|
507
|
+
cooling_tower = comp.to_CoolingTowerTwoSpeed.get
|
508
|
+
hardsize_cooling_tower_two_speed(cooling_tower)
|
509
|
+
runner.registerInfo("Autosized parameters from the sizing run have been set to CoolingTowerTwoSpeed #{cooling_tower.name}")
|
510
|
+
elsif comp.to_CoolingTowerVariableSpeed.is_initialized
|
511
|
+
cooling_tower = comp.to_CoolingTowerVariableSpeed.get
|
512
|
+
cooling_tower.applySizingValues
|
513
|
+
runner.registerInfo("Autosized parameters from the sizing run have been set to CoolingTowerVariableSpeed #{cooling_tower.name}")
|
514
|
+
end
|
515
|
+
end
|
516
|
+
end
|
371
517
|
|
372
518
|
# assuming average load ratio of chiller is 1/3 throughout the day
|
373
519
|
tank_vol = total_cooling_cap/3.0 * 3600 * lasting_hrs / (4182 * 1000 * secondary_delta_t) # heat capacity of water 4182J/kg.K, water density 1000g/m3, lasting 8 hours
|
@@ -380,7 +526,6 @@ class AddChilledWaterStorageTank < OpenStudio::Measure::ModelMeasure
|
|
380
526
|
|
381
527
|
sec_loop = OpenStudio::Model::PlantLoop.new(model)
|
382
528
|
sec_loop.setName("Chilled Water Secondary Loop")
|
383
|
-
selected_primary_loop = model.getPlantLoopByName("Chilled Water Loop").get
|
384
529
|
selected_primary_loop.setName("Chilled Water Primary Loop")
|
385
530
|
sizing_sec_plant = sec_loop.sizingPlant
|
386
531
|
sizing_sec_plant.setLoopType('Cooling')
|
@@ -391,21 +536,7 @@ class AddChilledWaterStorageTank < OpenStudio::Measure::ModelMeasure
|
|
391
536
|
sizing_pri_plant.setDesignLoopExitTemperature(primary_loop_sp)
|
392
537
|
sizing_pri_plant.setLoopDesignTemperatureDifference(primary_delta_t)
|
393
538
|
|
394
|
-
|
395
|
-
cw_loop = nil
|
396
|
-
model.getPlantLoops.each do |loop|
|
397
|
-
if loop.sizingPlant.loopType.to_s.downcase == 'condenser'
|
398
|
-
cw_loop = loop if cw_loop.nil?
|
399
|
-
# confirm if this condenser loop contains demand component of chiller that is in the selected_primary_loop
|
400
|
-
common_comps = cw_loop.demandComponents & selected_primary_loop.supplyComponents
|
401
|
-
chiller_in_both_loops = false
|
402
|
-
common_comps.each do |comp|
|
403
|
-
chiller_in_both_loops = true if comp.to_ChillerElectricEIR.is_initialized || comp.to_ChillerAbsorption.is_initialized || comp.to_ChillerAbsorptionIndirect.is_initialized
|
404
|
-
end
|
405
|
-
cw_loop = nil unless chiller_in_both_loops
|
406
|
-
end
|
407
|
-
end
|
408
|
-
# not necessarily can find a cw_loop as the existing primary chiller might be air cooled.
|
539
|
+
|
409
540
|
|
410
541
|
# add chilled water tank to the primary loop as demand and secondary loop as supply
|
411
542
|
chw_storage_tank = OpenStudio::Model::ThermalStorageChilledWaterStratified.new(model)
|