Module: OpenstudioStandards::ServiceWaterHeating
- Defined in:
- lib/openstudio-standards/service_water_heating/create_water_use.rb,
lib/openstudio-standards/service_water_heating/create_water_heater.rb,
lib/openstudio-standards/service_water_heating/create_piping_losses.rb,
lib/openstudio-standards/service_water_heating/create_water_heating_loop.rb
Overview
The ServiceWaterHeating module provides methods to create, modify, and get information about service water heating
Create Water Use collapse
-
.create_water_use(model, name: 'Main Water Use', flow_rate: 0.0, flow_rate_fraction_schedule: nil, water_use_temperature: 43.3, water_use_temperature_schedule: nil, sensible_fraction: 0.2, latent_fraction: 0.05, service_water_loop: nil, space: nil) ⇒ OpenStudio::Model::WaterUseEquipment
Creates a water use and attaches it to a service water loop and a space, if provided.
Create Water Heater collapse
-
.create_heatpump_water_heater(model, heat_pump_type: 'PumpedCondenser', water_heater_capacity: 500.0, water_heater_volume: OpenStudio.convert(80.0, 'gal', 'm^3').get, coefficient_of_performance: 2.8, electric_backup_capacity: 4500.0, on_cycle_parasitic_fuel_consumption_rate: 0.0, off_cycle_parasitic_fuel_consumption_rate: 0.0, service_water_temperature: OpenStudio.convert(125.0, 'F', 'C').get, service_water_temperature_schedule: nil, set_peak_use_flowrate: false, peak_flowrate: nil, flowrate_schedule: nil, water_heater_thermal_zone: nil, service_water_loop: nil, use_ems_control: false) ⇒ OpenStudio::Model::WaterHeaterMixed
Creates a heatpump water heater and attaches it to the supplied service water heating loop.
-
.create_water_heater(model, water_heater_capacity: nil, water_heater_volume: nil, water_heater_fuel: 'Electricity', on_cycle_parasitic_fuel_consumption_rate: 0.0, off_cycle_parasitic_fuel_consumption_rate: 0.0, service_water_temperature: 60.0, service_water_temperature_schedule: nil, set_peak_use_flowrate: false, peak_flowrate: nil, flowrate_schedule: nil, water_heater_thermal_zone: nil, number_of_water_heaters: 1, service_water_loop: nil) ⇒ OpenStudio::Model::WaterHeaterMixed
Creates a water heater and attaches it to the supplied service water heating loop.
Create Piping Losses collapse
-
.create_service_water_heating_piping_losses(model, service_water_loop, circulating: true, pipe_insulation_thickness: 0.0, floor_area: nil, number_of_stories: nil, pipe_length: 6.1, air_temperature: 21.1) ⇒ Boolean
Adds piping losses to a service water heating Loop.
Create Loop collapse
-
.create_booster_water_heating_loop(model, water_heater_capacity: 8000.0, water_heater_volume: OpenStudio.convert(6.0, 'gal', 'm^3').get, water_heater_fuel: 'Electricity', on_cycle_parasitic_fuel_consumption_rate: 0.0, off_cycle_parasitic_fuel_consumption_rate: 0.0, service_water_temperature: 82.2, service_water_temperature_schedule: nil, water_heater_thermal_zone: nil, service_water_loop: nil) ⇒ OpenStudio::Model::PlantLoop
Creates a booster water heater on its own loop and attaches it to the main service water heating loop.
-
.create_service_water_heating_loop(model, system_name: 'Service Water Loop', service_water_temperature: 60.0, service_water_pump_head: 29861.0, service_water_pump_motor_efficiency: 0.3, water_heater_capacity: nil, water_heater_volume: nil, water_heater_fuel: 'Electricity', on_cycle_parasitic_fuel_consumption_rate: 0.0, off_cycle_parasitic_fuel_consumption_rate: 0.0, water_heater_thermal_zone: nil, number_of_water_heaters: 1, add_piping_losses: false, pipe_insulation_thickness: 0.0127, floor_area: nil, number_of_stories: nil) ⇒ OpenStudio::Model::PlantLoop
Creates a service water heating loop.
Class Method Details
.create_booster_water_heating_loop(model, water_heater_capacity: 8000.0, water_heater_volume: OpenStudio.convert(6.0, 'gal', 'm^3').get, water_heater_fuel: 'Electricity', on_cycle_parasitic_fuel_consumption_rate: 0.0, off_cycle_parasitic_fuel_consumption_rate: 0.0, service_water_temperature: 82.2, service_water_temperature_schedule: nil, water_heater_thermal_zone: nil, service_water_loop: nil) ⇒ OpenStudio::Model::PlantLoop
Creates a booster water heater on its own loop and attaches it to the main service water heating loop.
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
# File 'lib/openstudio-standards/service_water_heating/create_water_heating_loop.rb', line 181 def self.create_booster_water_heating_loop(model, water_heater_capacity: 8000.0, water_heater_volume: OpenStudio.convert(6.0, 'gal', 'm^3').get, water_heater_fuel: 'Electricity', on_cycle_parasitic_fuel_consumption_rate: 0.0, off_cycle_parasitic_fuel_consumption_rate: 0.0, service_water_temperature: 82.2, service_water_temperature_schedule: nil, water_heater_thermal_zone: nil, service_water_loop: nil) if service_water_loop.nil? OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.ServiceWaterHeating', "#{_method_} requires the service_water_loop argument to couple the booster water heating loop with a heat exchanger.") return nil else OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ServiceWaterHeating', "Adding booster water heater to #{service_water_loop.name}") end water_heater_volume_gal = OpenStudio.convert(water_heater_volume, 'm^3', 'gal').get water_heater_capacity_kbtu_per_hr = OpenStudio.convert(water_heater_capacity, 'W', 'kBtu/hr').get # Booster water heating loop booster_service_water_loop = OpenStudio::Model::PlantLoop.new(model) booster_service_water_loop.setName('Booster Service Water Loop') # create and add booster water heater to loop booster_water_heater = OpenstudioStandards::ServiceWaterHeating.create_water_heater(model, water_heater_capacity: water_heater_capacity, water_heater_volume: water_heater_volume, water_heater_fuel: water_heater_fuel, on_cycle_parasitic_fuel_consumption_rate: on_cycle_parasitic_fuel_consumption_rate, off_cycle_parasitic_fuel_consumption_rate: off_cycle_parasitic_fuel_consumption_rate, service_water_temperature: service_water_temperature, service_water_temperature_schedule: service_water_temperature_schedule, water_heater_thermal_zone: water_heater_thermal_zone, service_water_loop: booster_service_water_loop) booster_water_heater.setName("#{water_heater_volume_gal}gal #{water_heater_fuel} Booster Water Heater - #{water_heater_capacity_kbtu_per_hr.round}kBtu/hr") booster_water_heater.setEndUseSubcategory('Booster') # Service water heating loop controls swh_temp_f = OpenStudio.convert(service_water_temperature, 'C', 'F').get swh_delta_t_r = 9.0 # 9F delta-T swh_delta_t_k = OpenStudio.convert(swh_delta_t_r, 'R', 'K').get swh_temp_sch = OpenstudioStandards::Schedules.create_constant_schedule_ruleset(model, service_water_temperature, name: "Service Water Booster Temp - #{swh_temp_f.round}F", schedule_type_limit: 'Temperature') swh_stpt_manager = OpenStudio::Model::SetpointManagerScheduled.new(model, swh_temp_sch) swh_stpt_manager.setName('Hot water booster setpoint manager') swh_stpt_manager.addToNode(booster_service_water_loop.supplyOutletNode) sizing_plant = booster_service_water_loop.sizingPlant sizing_plant.setLoopType('Heating') sizing_plant.setDesignLoopExitTemperature(service_water_temperature) sizing_plant.setLoopDesignTemperatureDifference(swh_delta_t_k) # Booster water heating pump swh_pump = OpenStudio::Model::PumpVariableSpeed.new(model) swh_pump.setName('Booster Water Loop Pump') swh_pump.setRatedPumpHead(0.0) # As if there is no circulation pump swh_pump.setRatedPowerConsumption(0.0) # As if there is no circulation pump swh_pump.setMotorEfficiency(1) swh_pump.setPumpControlType('Continuous') swh_pump.setMinimumFlowRate(0.0) swh_pump.addToNode(booster_service_water_loop.supplyInletNode) # Service water heating loop bypass pipes water_heater_bypass_pipe = OpenStudio::Model::PipeAdiabatic.new(model) booster_service_water_loop.addSupplyBranchForComponent(water_heater_bypass_pipe) coil_bypass_pipe = OpenStudio::Model::PipeAdiabatic.new(model) booster_service_water_loop.addDemandBranchForComponent(coil_bypass_pipe) supply_outlet_pipe = OpenStudio::Model::PipeAdiabatic.new(model) supply_outlet_pipe.addToNode(booster_service_water_loop.supplyOutletNode) demand_inlet_pipe = OpenStudio::Model::PipeAdiabatic.new(model) demand_inlet_pipe.addToNode(booster_service_water_loop.demandInletNode) demand_outlet_pipe = OpenStudio::Model::PipeAdiabatic.new(model) demand_outlet_pipe.addToNode(booster_service_water_loop.demandOutletNode) # Heat exchanger to supply the booster water heater with normal hot water from the main service water loop hx = OpenStudio::Model::HeatExchangerFluidToFluid.new(model) hx.setName('Booster Water Heating Heat Exchanger') hx.setHeatExchangeModelType('Ideal') hx.setControlType('UncontrolledOn') hx.setHeatTransferMeteringEndUseType('LoopToLoop') # Add the HX to the supply side of the booster loop hx.addToNode(booster_service_water_loop.supplyInletNode) # Add the HX to the demand side of the main service water loop service_water_loop.addDemandBranchForComponent(hx) # Add a plant component temperature source to the demand outlet # of the HX to represent the fact that the water used by the booster # would in reality be at the mains temperature. mains_src = OpenStudio::Model::PlantComponentTemperatureSource.new(model) mains_src.setName('Mains Water Makeup for SWH Booster') mains_src.addToNode(hx.demandOutletModelObject.get.to_Node.get) # use the site water mains temperature schedule if available, # otherwise use the annual average outdoor air temperature site_water_mains = model.getSiteWaterMainsTemperature if site_water_mains.temperatureSchedule.is_initialized water_mains_temp_sch = site_water_mains.temperatureSchedule.get elsif site_water_mains.annualAverageOutdoorAirTemperature.is_initialized mains_src_temp_c = site_water_mains.annualAverageOutdoorAirTemperature.get mains_src.setSourceTemperature(mains_src_temp_c) water_mains_temp_sch = OpenStudio::Model::ScheduleConstant.new(model) water_mains_temp_sch.setName('Booster Water Makeup Temperature') water_mains_temp_sch.setValue(mains_src_temp_c) else # assume 50F mains_src_temp_c = OpenStudio.convert(50.0, 'F', 'C').get mains_src.setSourceTemperature(mains_src_temp_c) water_mains_temp_sch = OpenStudio::Model::ScheduleConstant.new(model) water_mains_temp_sch.setName('Booster Water Makeup Temperature') water_mains_temp_sch.setValue(mains_src_temp_c) end mains_src.setTemperatureSpecificationType('Scheduled') mains_src.setSourceTemperatureSchedule(water_mains_temp_sch) return booster_service_water_loop end |
.create_heatpump_water_heater(model, heat_pump_type: 'PumpedCondenser', water_heater_capacity: 500.0, water_heater_volume: OpenStudio.convert(80.0, 'gal', 'm^3').get, coefficient_of_performance: 2.8, electric_backup_capacity: 4500.0, on_cycle_parasitic_fuel_consumption_rate: 0.0, off_cycle_parasitic_fuel_consumption_rate: 0.0, service_water_temperature: OpenStudio.convert(125.0, 'F', 'C').get, service_water_temperature_schedule: nil, set_peak_use_flowrate: false, peak_flowrate: nil, flowrate_schedule: nil, water_heater_thermal_zone: nil, service_water_loop: nil, use_ems_control: false) ⇒ OpenStudio::Model::WaterHeaterMixed
Creates a heatpump water heater and attaches it to the supplied service water heating loop.
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 |
# File 'lib/openstudio-standards/service_water_heating/create_water_heater.rb', line 198 def self.create_heatpump_water_heater(model, heat_pump_type: 'PumpedCondenser', water_heater_capacity: 500.0, water_heater_volume: OpenStudio.convert(80.0, 'gal', 'm^3').get, coefficient_of_performance: 2.8, electric_backup_capacity: 4500.0, on_cycle_parasitic_fuel_consumption_rate: 0.0, off_cycle_parasitic_fuel_consumption_rate: 0.0, service_water_temperature: OpenStudio.convert(125.0, 'F', 'C').get, service_water_temperature_schedule: nil, set_peak_use_flowrate: false, peak_flowrate: nil, flowrate_schedule: nil, water_heater_thermal_zone: nil, service_water_loop: nil, use_ems_control: false) # create heat pump water heater if heat_pump_type == 'WrappedCondenser' hpwh = OpenStudio::Model::WaterHeaterHeatPumpWrappedCondenser.new(model) elsif heat_pump_type == 'PumpedCondenser' hpwh = OpenStudio::Model::WaterHeaterHeatPump.new(model) end # calculate tank height and radius water_heater_capacity_kbtu_per_hr = OpenStudio.convert(water_heater_capacity, 'W', 'kBtu/hr').get hpwh_vol_gal = OpenStudio.convert(water_heater_volume, 'm^3', 'gal').get tank_height = (0.0188 * hpwh_vol_gal) + 0.0935 # linear relationship that gets GE height at 50 gal and AO Smith height at 80 gal tank_radius = (0.9 * water_heater_volume / (Math::PI * tank_height))**0.5 tank_surface_area = 2.0 * Math::PI * tank_radius * (tank_radius + tank_height) tank_ua = 3.9 # default ua assumption u_tank = (5.678 * tank_ua) / OpenStudio.convert(tank_surface_area, 'm^2', 'ft^2').get hpwh.setName("#{hpwh_vol_gal.round}gal Heat Pump Water Heater - #{water_heater_capacity_kbtu_per_hr.round(0)}kBtu/hr") # set min/max HPWH operating temperature limit hpwh_op_min_temp_c = OpenStudio.convert(45.0, 'F', 'C').get hpwh_op_max_temp_c = OpenStudio.convert(120.0, 'F', 'C').get if heat_pump_type == 'WrappedCondenser' hpwh.setMinimumInletAirTemperatureforCompressorOperation(hpwh_op_min_temp_c) hpwh.setMaximumInletAirTemperatureforCompressorOperation(hpwh_op_max_temp_c) # set sensor heights if hpwh_vol_gal <= 50.0 hpwh.setDeadBandTemperatureDifference(0.5) h_ue = (1 - (3.5 / 12.0)) * tank_height # in the 4th node of the tank (counting from top) h_le = (1 - (10.5 / 12.0)) * tank_height # in the 11th node of the tank (counting from top) h_condtop = (1 - (5.5 / 12.0)) * tank_height # in the 6th node of the tank (counting from top) h_condbot = (1 - (10.99 / 12.0)) * tank_height # in the 11th node of the tank h_hpctrl = (1 - (2.5 / 12.0)) * tank_height # in the 3rd node of the tank hpwh.setControlSensor1HeightInStratifiedTank(h_hpctrl) hpwh.setControlSensor1Weight(1.0) hpwh.setControlSensor2HeightInStratifiedTank(h_hpctrl) else hpwh.setDeadBandTemperatureDifference(3.89) h_ue = (1 - (3.5 / 12.0)) * tank_height # in the 3rd node of the tank (counting from top) h_le = (1 - (9.5 / 12.0)) * tank_height # in the 10th node of the tank (counting from top) h_condtop = (1 - (5.5 / 12.0)) * tank_height # in the 6th node of the tank (counting from top) h_condbot = 0.01 # bottom node h_hpctrl_up = (1 - (2.5 / 12.0)) * tank_height # in the 3rd node of the tank h_hpctrl_low = (1 - (8.5 / 12.0)) * tank_height # in the 9th node of the tank hpwh.setControlSensor1HeightInStratifiedTank(h_hpctrl_up) hpwh.setControlSensor1Weight(0.75) hpwh.setControlSensor2HeightInStratifiedTank(h_hpctrl_low) end hpwh.setCondenserBottomLocation(h_condbot) hpwh.setCondenserTopLocation(h_condtop) hpwh.setTankElementControlLogic('MutuallyExclusive') hpwh.autocalculateEvaporatorAirFlowRate elsif heat_pump_type == 'PumpedCondenser' hpwh.setDeadBandTemperatureDifference(3.89) hpwh.autosizeEvaporatorAirFlowRate end # set heat pump water heater properties hpwh.setFanPlacement('DrawThrough') hpwh.setOnCycleParasiticElectricLoad(0.0) hpwh.setOffCycleParasiticElectricLoad(0.0) hpwh.setParasiticHeatRejectionLocation('Outdoors') # set temperature setpoint schedule if service_water_temperature_schedule.nil? # service water heating loop controls swh_temp_c = service_water_temperature swh_temp_f = OpenStudio.convert(swh_temp_c, 'C', 'F').get swh_delta_t_r = 9.0 # 9F delta-T swh_temp_c = OpenStudio.convert(swh_temp_f, 'F', 'C').get swh_delta_t_k = OpenStudio.convert(swh_delta_t_r, 'R', 'K').get service_water_temperature_schedule = OpenstudioStandards::Schedules.create_constant_schedule_ruleset(model, swh_temp_c, name: "Heat Pump Water Heater Temp - #{swh_temp_f.round}F", schedule_type_limit: 'Temperature') end hpwh.setCompressorSetpointTemperatureSchedule(service_water_temperature_schedule) # coil curves hpwh_cap = OpenStudio::Model::CurveBiquadratic.new(model) hpwh_cap.setName('HPWH-Cap-fT') hpwh_cap.setCoefficient1Constant(0.563) hpwh_cap.setCoefficient2x(0.0437) hpwh_cap.setCoefficient3xPOW2(0.000039) hpwh_cap.setCoefficient4y(0.0055) hpwh_cap.setCoefficient5yPOW2(-0.000148) hpwh_cap.setCoefficient6xTIMESY(-0.000145) hpwh_cap.setMinimumValueofx(0.0) hpwh_cap.setMaximumValueofx(100.0) hpwh_cap.setMinimumValueofy(0.0) hpwh_cap.setMaximumValueofy(100.0) hpwh_cop = OpenStudio::Model::CurveBiquadratic.new(model) hpwh_cop.setName('HPWH-COP-fT') hpwh_cop.setCoefficient1Constant(1.1332) hpwh_cop.setCoefficient2x(0.063) hpwh_cop.setCoefficient3xPOW2(-0.0000979) hpwh_cop.setCoefficient4y(-0.00972) hpwh_cop.setCoefficient5yPOW2(-0.0000214) hpwh_cop.setCoefficient6xTIMESY(-0.000686) hpwh_cop.setMinimumValueofx(0.0) hpwh_cop.setMaximumValueofx(100.0) hpwh_cop.setMinimumValueofy(0.0) hpwh_cop.setMaximumValueofy(100.0) # create DX coil object if heat_pump_type == 'WrappedCondenser' coil = hpwh.dXCoil.to_CoilWaterHeatingAirToWaterHeatPumpWrapped.get coil.setRatedCondenserWaterTemperature(48.89) coil.autocalculateRatedEvaporatorAirFlowRate elsif heat_pump_type == 'PumpedCondenser' coil = hpwh.dXCoil.to_CoilWaterHeatingAirToWaterHeatPump.get coil.autosizeRatedEvaporatorAirFlowRate end # set coil properties coil.setName("#{hpwh.name} Coil") coil.setRatedHeatingCapacity(water_heater_capacity) coil.setRatedCOP(coefficient_of_performance) coil.setRatedSensibleHeatRatio(0.88) # default sensible_heat_ratio assumption coil.setRatedEvaporatorInletAirDryBulbTemperature(OpenStudio.convert(67.5, 'F', 'C').get) coil.setRatedEvaporatorInletAirWetBulbTemperature(OpenStudio.convert(56.426, 'F', 'C').get) coil.setEvaporatorFanPowerIncludedinRatedCOP(true) coil.setEvaporatorAirTemperatureTypeforCurveObjects('WetBulbTemperature') coil.setHeatingCapacityFunctionofTemperatureCurve(hpwh_cap) coil.setHeatingCOPFunctionofTemperatureCurve(hpwh_cop) coil.setMaximumAmbientTemperatureforCrankcaseHeaterOperation(0.0) # set tank properties if heat_pump_type == 'WrappedCondenser' tank = hpwh.tank.to_WaterHeaterStratified.get tank.setTankHeight(tank_height) tank.setHeaterPriorityControl('MasterSlave') if hpwh_vol_gal <= 50.0 tank.setHeater1DeadbandTemperatureDifference(25.0) tank.setHeater2DeadbandTemperatureDifference(30.0) else tank.setHeater1DeadbandTemperatureDifference(18.5) tank.setHeater2DeadbandTemperatureDifference(3.89) end hpwh_bottom_element_sp = OpenStudio::Model::ScheduleConstant.new(model) hpwh_bottom_element_sp.setName("#{hpwh.name} BottomElementSetpoint") hpwh_top_element_sp = OpenStudio::Model::ScheduleConstant.new(model) hpwh_top_element_sp.setName("#{hpwh.name} TopElementSetpoint") tank.setHeater1Capacity(electric_backup_capacity) tank.setHeater1Height(h_ue) tank.setHeater1SetpointTemperatureSchedule(hpwh_top_element_sp) # Overwritten later by EMS tank.setHeater2Capacity(electric_backup_capacity) tank.setHeater2Height(h_le) tank.setHeater2SetpointTemperatureSchedule(hpwh_bottom_element_sp) tank.setUniformSkinLossCoefficientperUnitAreatoAmbientTemperature(u_tank) tank.setNumberofNodes(12) tank.setAdditionalDestratificationConductivity(0) tank.setNode1AdditionalLossCoefficient(0) tank.setNode2AdditionalLossCoefficient(0) tank.setNode3AdditionalLossCoefficient(0) tank.setNode4AdditionalLossCoefficient(0) tank.setNode5AdditionalLossCoefficient(0) tank.setNode6AdditionalLossCoefficient(0) tank.setNode7AdditionalLossCoefficient(0) tank.setNode8AdditionalLossCoefficient(0) tank.setNode9AdditionalLossCoefficient(0) tank.setNode10AdditionalLossCoefficient(0) tank.setNode11AdditionalLossCoefficient(0) tank.setNode12AdditionalLossCoefficient(0) tank.setUseSideDesignFlowRate(0.9 * water_heater_volume / 60.1) tank.setSourceSideDesignFlowRate(0) tank.setSourceSideFlowControlMode('') tank.setSourceSideInletHeight(0) tank.setSourceSideOutletHeight(0) elsif heat_pump_type == 'PumpedCondenser' tank = hpwh.tank.to_WaterHeaterMixed.get tank.setDeadbandTemperatureDifference(3.89) tank.setHeaterControlType('Cycle') tank.setHeaterMaximumCapacity(electric_backup_capacity) end tank.setName("#{hpwh.name} Tank") tank.setEndUseSubcategory('Service Hot Water') tank.setTankVolume(0.9 * water_heater_volume) tank.setMaximumTemperatureLimit(90.0) tank.setHeaterFuelType('Electricity') tank.setHeaterThermalEfficiency(1.0) tank.setOffCycleParasiticFuelConsumptionRate(off_cycle_parasitic_fuel_consumption_rate) tank.setOffCycleParasiticFuelType('Electricity') tank.setOnCycleParasiticFuelConsumptionRate(on_cycle_parasitic_fuel_consumption_rate) tank.setOnCycleParasiticFuelType('Electricity') # set fan properties fan = hpwh.fan.to_FanOnOff.get fan.setName("#{hpwh.name} Fan") fan_power = 0.0462 # watts per cfm if hpwh_vol_gal <= 50.0 fan.setFanEfficiency(23.0 / fan_power * OpenStudio.convert(1.0, 'ft^3/min', 'm^3/s').get) fan.setPressureRise(23.0) else fan.setFanEfficiency(65.0 / fan_power * OpenStudio.convert(1.0, 'ft^3/min', 'm^3/s').get) fan.setPressureRise(65.0) end # determine maximum flow rate from water heater capacity # use 5.035E-5 m^3/s/W from EnergyPlus used to autocalculate the evaporator air flow rate in WaterHeater:HeatPump:PumpedCondenser and Coil:WaterHeating:AirToWaterHeatPump:Pumped fan_flow_rate_m3_per_s = water_heater_capacity * 5.035e-5 fan.setMaximumFlowRate(fan_flow_rate_m3_per_s) fan.setMotorEfficiency(1.0) fan.setMotorInAirstreamFraction(1.0) fan.setEndUseSubcategory('Service Hot Water') if water_heater_thermal_zone.nil? # add in schedules for Tamb, RHamb, and the compressor # assume the water heater is indoors at 71.6F / 22C default_water_heater_ambient_temp_sch = OpenstudioStandards::Schedules.create_constant_schedule_ruleset(model, OpenStudio.convert(71.6, 'F', 'C').get, name: 'Water Heater Ambient Temp Schedule 70F', schedule_type_limit: 'Temperature') tank.setAmbientTemperatureIndicator('Schedule') tank.setAmbientTemperatureSchedule(default_water_heater_ambient_temp_sch) tank.resetAmbientTemperatureThermalZone hpwh_rhamb = OpenStudio::Model::ScheduleConstant.new(model) hpwh_rhamb.setName("#{hpwh.name} Ambient Humidity Schedule") hpwh_rhamb.setValue(0.5) hpwh.setInletAirConfiguration('Schedule') hpwh.setInletAirTemperatureSchedule(default_water_heater_ambient_temp_sch) hpwh.setInletAirHumiditySchedule(hpwh_rhamb) hpwh.setCompressorLocation('Schedule') hpwh.setCompressorAmbientTemperatureSchedule(default_water_heater_ambient_temp_sch) else hpwh.addToThermalZone(water_heater_thermal_zone) hpwh.setInletAirConfiguration('ZoneAirOnly') hpwh.setCompressorLocation('Zone') tank.setAmbientTemperatureIndicator('ThermalZone') tank.setAmbientTemperatureThermalZone(water_heater_thermal_zone) tank.resetAmbientTemperatureSchedule end if set_peak_use_flowrate rated_flow_rate_m3_per_s = peak_flowrate rated_flow_rate_gal_per_min = OpenStudio.convert(rated_flow_rate_m3_per_s, 'm^3/s', 'gal/min').get tank.setPeakUseFlowRate(rated_flow_rate_m3_per_s) tank.setUseFlowRateFractionSchedule(flowrate_schedule) unless flowrate_schedule.nil? end # add EMS for overriding HPWH setpoints schedules (for upper/lower heating element in water tank and compressor in heat pump) if heat_pump_type == 'WrappedCondenser' && use_ems_control std = Standard.build('90.1-2013') hpwh_name_ems_friendly = std.ems_friendly_name(hpwh.name) # create an ambient temperature sensor for the air that blows through the HPWH evaporator if water_heater_thermal_zone.nil? # assume the condenser is outside amb_temp_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Site Outdoor Air Drybulb Temperature') amb_temp_sensor.setName("#{hpwh_name_ems_friendly}_amb_temp") amb_temp_sensor.setKeyName('Environment') else amb_temp_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Zone Mean Air Temperature') amb_temp_sensor.setName("#{hpwh_name_ems_friendly}_amb_temp") amb_temp_sensor.setKeyName(water_heater_thermal_zone.name.to_s) end # create actuator for heat pump compressor if service_water_temperature_schedule.to_ScheduleConstant.is_initialized service_water_temperature_schedule = service_water_temperature_schedule.to_ScheduleConstant.get schedule_type = 'Schedule:Constant' elsif service_water_temperature_schedule.to_ScheduleCompact.is_initialized service_water_temperature_schedule = service_water_temperature_schedule.to_ScheduleCompact.get schedule_type = 'Schedule:Compact' elsif service_water_temperature_schedule.to_ScheduleRuleset.is_initialized service_water_temperature_schedule = service_water_temperature_schedule.to_ScheduleRuleset.get schedule_type = 'Schedule:Year' else OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.ServiceWaterHeating', "Unsupported schedule type for HPWH setpoint schedule #{service_water_temperature_schedule.name}.") return false end hpwhschedoverride_actuator = OpenStudio::Model::EnergyManagementSystemActuator.new(service_water_temperature_schedule, schedule_type, 'Schedule Value') hpwhschedoverride_actuator.setName("#{hpwh_name_ems_friendly}_HPWHSchedOverride") # create actuator for lower heating element in water tank leschedoverride_actuator = OpenStudio::Model::EnergyManagementSystemActuator.new(hpwh_bottom_element_sp, 'Schedule:Constant', 'Schedule Value') leschedoverride_actuator.setName("#{hpwh_name_ems_friendly}_LESchedOverride") # create actuator for upper heating element in water tank ueschedoverride_actuator = OpenStudio::Model::EnergyManagementSystemActuator.new(hpwh_top_element_sp, 'Schedule:Constant', 'Schedule Value') ueschedoverride_actuator.setName("#{hpwh_name_ems_friendly}_UESchedOverride") # create sensor for heat pump compressor t_set_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Schedule Value') t_set_sensor.setName("#{hpwh_name_ems_friendly}_T_set") t_set_sensor.setKeyName(service_water_temperature_schedule.name.to_s) # define control configuration t_offset = 9.0 # deg-C # get tank specifications upper_element_db = tank.heater1DeadbandTemperatureDifference # define control logic hpwh_ctrl_program = OpenStudio::Model::EnergyManagementSystemProgram.new(model) hpwh_ctrl_program.setName("#{hpwh_name_ems_friendly}_Control") hpwh_ctrl_program.addLine("SET #{hpwhschedoverride_actuator.name} = #{t_set_sensor.name}") # lockout hp when ambient temperature is either too high or too low hpwh_ctrl_program.addLine("IF (#{amb_temp_sensor.name}<#{hpwh_op_min_temp_c}) || (#{amb_temp_sensor.name}>#{hpwh_op_max_temp_c})") hpwh_ctrl_program.addLine("SET #{ueschedoverride_actuator.name} = #{t_set_sensor.name}") hpwh_ctrl_program.addLine("SET #{leschedoverride_actuator.name} = #{t_set_sensor.name}") hpwh_ctrl_program.addLine('ELSE') # upper element setpoint temperature hpwh_ctrl_program.addLine("SET #{ueschedoverride_actuator.name} = #{t_set_sensor.name} - #{t_offset}") # upper element cut-in temperature hpwh_ctrl_program.addLine("SET #{ueschedoverride_actuator.name}_cut_in = #{ueschedoverride_actuator.name} - #{upper_element_db}") # lower element disabled hpwh_ctrl_program.addLine("SET #{leschedoverride_actuator.name} = 0") # lower element disabled hpwh_ctrl_program.addLine("SET #{leschedoverride_actuator.name}_cut_in = 0") hpwh_ctrl_program.addLine('ENDIF') # create a program calling manager program_calling_manager = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model) program_calling_manager.setName("#{hpwh_name_ems_friendly}_ProgramManager") program_calling_manager.setCallingPoint('InsideHVACSystemIterationLoop') program_calling_manager.addProgram(hpwh_ctrl_program) end # add the water heater to the service water loop if provided unless service_water_loop.nil? service_water_loop.addSupplyBranchForComponent(tank) end OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ServiceWaterHeating', "Added heat pump water heater called #{tank.name}") return hpwh end |
.create_service_water_heating_loop(model, system_name: 'Service Water Loop', service_water_temperature: 60.0, service_water_pump_head: 29861.0, service_water_pump_motor_efficiency: 0.3, water_heater_capacity: nil, water_heater_volume: nil, water_heater_fuel: 'Electricity', on_cycle_parasitic_fuel_consumption_rate: 0.0, off_cycle_parasitic_fuel_consumption_rate: 0.0, water_heater_thermal_zone: nil, number_of_water_heaters: 1, add_piping_losses: false, pipe_insulation_thickness: 0.0127, floor_area: nil, number_of_stories: nil) ⇒ OpenStudio::Model::PlantLoop
Creates a service water heating loop.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/openstudio-standards/service_water_heating/create_water_heating_loop.rb', line 31 def self.create_service_water_heating_loop(model, system_name: 'Service Water Loop', service_water_temperature: 60.0, service_water_pump_head: 29861.0, service_water_pump_motor_efficiency: 0.3, water_heater_capacity: nil, water_heater_volume: nil, water_heater_fuel: 'Electricity', on_cycle_parasitic_fuel_consumption_rate: 0.0, off_cycle_parasitic_fuel_consumption_rate: 0.0, water_heater_thermal_zone: nil, number_of_water_heaters: 1, add_piping_losses: false, pipe_insulation_thickness: 0.0127, floor_area: nil, number_of_stories: nil) # create service water heating loop service_water_loop = OpenStudio::Model::PlantLoop.new(model) service_water_loop.setMinimumLoopTemperature(10.0) if service_water_temperature > 60.0 service_water_loop.setMaximumLoopTemperature(service_water_temperature) else service_water_loop.setMaximumLoopTemperature(60.0) end if system_name.nil? system_name = 'Service Water Loop' end service_water_loop.setName(system_name) # service water heating loop controls swh_temp_f = OpenStudio.convert(service_water_temperature, 'C', 'F').get swh_delta_t_r = 9.0 # 9F delta-T swh_delta_t_k = OpenStudio.convert(swh_delta_t_r, 'R', 'K').get swh_temp_sch = OpenstudioStandards::Schedules.create_constant_schedule_ruleset(model, service_water_temperature, name: "Service Water Loop Temp - #{swh_temp_f.round}F", schedule_type_limit: 'Temperature') swh_stpt_manager = OpenStudio::Model::SetpointManagerScheduled.new(model, swh_temp_sch) swh_stpt_manager.setName('Service hot water setpoint manager') swh_stpt_manager.addToNode(service_water_loop.supplyOutletNode) sizing_plant = service_water_loop.sizingPlant sizing_plant.setLoopType('Heating') sizing_plant.setDesignLoopExitTemperature(service_water_temperature) sizing_plant.setLoopDesignTemperatureDifference(swh_delta_t_k) # determine if circulating or non-circulating based on supplied head pressure if service_water_pump_head.nil? || service_water_pump_head <= 1 # set pump head pressure to near zero if there is no circulation pump service_water_pump_head = 0.001 service_water_pump_motor_efficiency = 1 circulating = false else circulating = true end # add pump if circulating swh_pump = OpenStudio::Model::PumpConstantSpeed.new(model) swh_pump.setName("#{service_water_loop.name} Circulator Pump") swh_pump.setPumpControlType('Intermittent') else swh_pump = OpenStudio::Model::PumpVariableSpeed.new(model) swh_pump.setName("#{service_water_loop.name} Water Mains Pressure Driven") swh_pump.setPumpControlType('Continuous') end swh_pump.setRatedPumpHead(service_water_pump_head.to_f) swh_pump.setMotorEfficiency(service_water_pump_motor_efficiency) swh_pump.addToNode(service_water_loop.supplyInletNode) # add water heater case water_heater_fuel when 'None' # don't add a water heater when 'HeatPump' OpenstudioStandards::ServiceWaterHeating.create_heatpump_water_heater(model, water_heater_capacity: water_heater_capacity, water_heater_volume: water_heater_volume, on_cycle_parasitic_fuel_consumption_rate: on_cycle_parasitic_fuel_consumption_rate, off_cycle_parasitic_fuel_consumption_rate: off_cycle_parasitic_fuel_consumption_rate, service_water_temperature: service_water_temperature, service_water_temperature_schedule: swh_temp_sch, set_peak_use_flowrate: false, peak_flowrate: 0.0, flowrate_schedule: nil, water_heater_thermal_zone: water_heater_thermal_zone, service_water_loop: service_water_loop, use_ems_control: false) else OpenstudioStandards::ServiceWaterHeating.create_water_heater(model, water_heater_capacity: water_heater_capacity, water_heater_volume: water_heater_volume, water_heater_fuel: water_heater_fuel, on_cycle_parasitic_fuel_consumption_rate: on_cycle_parasitic_fuel_consumption_rate, off_cycle_parasitic_fuel_consumption_rate: off_cycle_parasitic_fuel_consumption_rate, service_water_temperature: service_water_temperature, service_water_temperature_schedule: swh_temp_sch, set_peak_use_flowrate: false, peak_flowrate: 0.0, flowrate_schedule: nil, water_heater_thermal_zone: water_heater_thermal_zone, number_of_water_heaters: number_of_water_heaters, service_water_loop: service_water_loop) end # add pipe losses if requested if add_piping_losses OpenstudioStandards::ServiceWaterHeating.create_service_water_heating_piping_losses(model, service_water_loop, circulating: circulating, pipe_insulation_thickness: pipe_insulation_thickness, floor_area: floor_area, number_of_stories: number_of_stories) end # service water heating loop bypass pipes water_heater_bypass_pipe = OpenStudio::Model::PipeAdiabatic.new(model) service_water_loop.addSupplyBranchForComponent(water_heater_bypass_pipe) coil_bypass_pipe = OpenStudio::Model::PipeAdiabatic.new(model) service_water_loop.addDemandBranchForComponent(coil_bypass_pipe) supply_outlet_pipe = OpenStudio::Model::PipeAdiabatic.new(model) supply_outlet_pipe.addToNode(service_water_loop.supplyOutletNode) demand_outlet_pipe = OpenStudio::Model::PipeAdiabatic.new(model) demand_outlet_pipe.addToNode(service_water_loop.demandOutletNode) if circulating OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ServiceWaterHeating', "Added circulating SWH loop called #{service_water_loop.name}") else OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ServiceWaterHeating', "Added non-circulating SWH loop called #{service_water_loop.name}") end return service_water_loop end |
.create_service_water_heating_piping_losses(model, service_water_loop, circulating: true, pipe_insulation_thickness: 0.0, floor_area: nil, number_of_stories: nil, pipe_length: 6.1, air_temperature: 21.1) ⇒ Boolean
Adds piping losses to a service water heating Loop. Assumes the piping system use insulated 0.75 inch copper piping. For circulating systems, assume length of piping is proportional to the building floor area and number of stories. For non-circulating systems, assume that the water heaters are close to the point of use.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/openstudio-standards/service_water_heating/create_piping_losses.rb', line 24 def self.create_service_water_heating_piping_losses(model, service_water_loop, circulating: true, pipe_insulation_thickness: 0.0, floor_area: nil, number_of_stories: nil, pipe_length: 6.1, air_temperature: 21.1) # Estimate pipe length if circulating # For circulating systems, get pipe length based on the size of the building. # Formula from A.3.1 PrototypeModelEnhancements_2014_0.pdf # get the floor area floor_area = model.getBuilding.floorArea if floor_area.nil? floor_area_ft2 = OpenStudio.convert(floor_area, 'm^2', 'ft^2').get # get the number of stories number_of_stories = model.getBuilding.buildingStories.size if number_of_stories.nil? # calculate the piping length pipe_length_ft = 2.0 * (Math.sqrt(floor_area_ft2 / number_of_stories) + (10.0 * (number_of_stories - 1.0))) OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ServiceWaterHeating', "Pipe length #{pipe_length_ft.round}ft = 2.0 * ( (#{floor_area_ft2.round}ft2 / #{number_of_stories} stories)^0.5 + (10.0ft * (#{number_of_stories} stories - 1.0) ) )") else # For non-circulating systems, assume water heater is close to point of use # get pipe length pipe_length_m = pipe_length.nil? ? 6.1 : pipe_length pipe_length_ft = OpenStudio.convert(pipe_length_m, 'm', 'ft').get OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ServiceWaterHeating', "Pipe length #{pipe_length_ft.round}ft. For non-circulating systems, assume water heater is close to point of use.") end # For systems whose water heater object represents multiple pieces # of equipment, multiply the piping length by the number of pieces of equipment. service_water_loop.supplyComponents('OS_WaterHeater_Mixed'.to_IddObjectType).each do |sc| next unless sc.to_WaterHeaterMixed.is_initialized water_heater = sc.to_WaterHeaterMixed.get # get number of water heaters if water_heater.additionalProperties.getFeatureAsInteger('component_quantity').is_initialized comp_qty = water_heater.additionalProperties.getFeatureAsInteger('component_quantity').get else comp_qty = 1 end # if more than 1 water heater, multiply the pipe length by the number of water heaters, # unless the user has specified a pipe length if comp_qty > 1 && pipe_length.nil? OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ServiceWaterHeating', "Piping length has been multiplied by #{comp_qty}X because #{water_heater.name} represents #{comp_qty} pieces of equipment.") pipe_length_ft *= comp_qty break end end # Service water heating piping heat loss scheduled air temperature air_temperature_f = OpenStudio.convert(air_temperature, 'C', 'F').get swh_piping_air_temp_sch = OpenstudioStandards::Schedules.create_constant_schedule_ruleset(model, air_temperature, name: "#{service_water_loop.name} Piping Air Temp - #{air_temperature_f.round}F", schedule_type_limit: 'Temperature') # Service water heating piping heat loss scheduled air velocity swh_piping_air_velocity_m_per_s = 0.3 swh_piping_air_velocity_mph = OpenStudio.convert(swh_piping_air_velocity_m_per_s, 'm/s', 'mile/hr').get swh_piping_air_velocity_sch = OpenstudioStandards::Schedules.create_constant_schedule_ruleset(model, swh_piping_air_velocity_m_per_s, name: "#{service_water_loop.name} Piping Air Velocity - #{swh_piping_air_velocity_mph.round(2)}mph") # Material for 3/4in type L (heavy duty) copper pipe copper_pipe = OpenStudio::Model::StandardOpaqueMaterial.new(model) copper_pipe.setName('Copper pipe 0.75in type L') copper_pipe.setRoughness('Smooth') copper_pipe.setThickness(OpenStudio.convert(0.045, 'in', 'm').get) copper_pipe.setThermalConductivity(386.0) copper_pipe.setDensity(OpenStudio.convert(556, 'lb/ft^3', 'kg/m^3').get) copper_pipe.setSpecificHeat(OpenStudio.convert(0.092, 'Btu/lb*R', 'J/kg*K').get) copper_pipe.setThermalAbsorptance(0.9) # @todo find reference for property copper_pipe.setSolarAbsorptance(0.7) # @todo find reference for property copper_pipe.setVisibleAbsorptance(0.7) # @todo find reference for property # Construction for pipe pipe_construction = OpenStudio::Model::Construction.new(model) # Add insulation material to insulated pipe if pipe_insulation_thickness > 0 # Material for fiberglass insulation # R-value from Owens-Corning 1/2in fiberglass pipe insulation # https://www.grainger.com/product/OWENS-CORNING-1-2-Thick-40PP22 # but modified until simulated heat loss = 17.7 Btu/hr/ft of pipe with 140F water and 70F air pipe_insulation_thickness_in = OpenStudio.convert(pipe_insulation_thickness, 'm', 'in').get insulation = OpenStudio::Model::StandardOpaqueMaterial.new(model) insulation.setName("Fiberglass batt #{pipe_insulation_thickness_in.round(2)}in") insulation.setRoughness('Smooth') insulation.setThickness(OpenStudio.convert(pipe_insulation_thickness_in, 'in', 'm').get) insulation.setThermalConductivity(OpenStudio.convert(0.46, 'Btu*in/hr*ft^2*R', 'W/m*K').get) insulation.setDensity(OpenStudio.convert(0.7, 'lb/ft^3', 'kg/m^3').get) insulation.setSpecificHeat(OpenStudio.convert(0.2, 'Btu/lb*R', 'J/kg*K').get) insulation.setThermalAbsorptance(0.9) # Irrelevant for Pipe:Indoor; no radiation model is used insulation.setSolarAbsorptance(0.7) # Irrelevant for Pipe:Indoor; no radiation model is used insulation.setVisibleAbsorptance(0.7) # Irrelevant for Pipe:Indoor; no radiation model is used pipe_construction.setName("Copper pipe 0.75in type L with #{pipe_insulation_thickness_in.round(2)}in fiberglass batt") pipe_construction.setLayers([insulation, copper_pipe]) else pipe_construction.setName('Uninsulated copper pipe 0.75in type L') pipe_construction.setLayers([copper_pipe]) end heat_loss_pipe = OpenStudio::Model::PipeIndoor.new(model) heat_loss_pipe.setName("#{service_water_loop.name} Pipe #{pipe_length_ft.round}ft") heat_loss_pipe.setEnvironmentType('Schedule') heat_loss_pipe.setAmbientTemperatureSchedule(swh_piping_air_temp_sch) heat_loss_pipe.setAmbientAirVelocitySchedule(swh_piping_air_velocity_sch) heat_loss_pipe.setConstruction(pipe_construction) heat_loss_pipe.setPipeInsideDiameter(OpenStudio.convert(0.785, 'in', 'm').get) heat_loss_pipe.setPipeLength(OpenStudio.convert(pipe_length_ft, 'ft', 'm').get) heat_loss_pipe.addToNode(service_water_loop.demandInletNode) OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ServiceWaterHeating', "Added #{pipe_length_ft.round}ft of #{pipe_construction.name} losing heat to #{air_temperature_f.round}F air to #{service_water_loop.name}.") return true end |
.create_water_heater(model, water_heater_capacity: nil, water_heater_volume: nil, water_heater_fuel: 'Electricity', on_cycle_parasitic_fuel_consumption_rate: 0.0, off_cycle_parasitic_fuel_consumption_rate: 0.0, service_water_temperature: 60.0, service_water_temperature_schedule: nil, set_peak_use_flowrate: false, peak_flowrate: nil, flowrate_schedule: nil, water_heater_thermal_zone: nil, number_of_water_heaters: 1, service_water_loop: nil) ⇒ OpenStudio::Model::WaterHeaterMixed
Creates a water heater and attaches it to the supplied service water heating loop.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/openstudio-standards/service_water_heating/create_water_heater.rb', line 28 def self.create_water_heater(model, water_heater_capacity: nil, water_heater_volume: nil, water_heater_fuel: 'Electricity', on_cycle_parasitic_fuel_consumption_rate: 0.0, off_cycle_parasitic_fuel_consumption_rate: 0.0, service_water_temperature: 60.0, service_water_temperature_schedule: nil, set_peak_use_flowrate: false, peak_flowrate: nil, flowrate_schedule: nil, water_heater_thermal_zone: nil, number_of_water_heaters: 1, service_water_loop: nil) # create water heater object # @todo Standards - Change water heater methodology to follow 'Model Enhancements Appendix A.' water_heater = OpenStudio::Model::WaterHeaterMixed.new(model) # default water heater capacity if nil if water_heater_capacity.nil? water_heater_capacity = OpenStudio.convert(200.0, 'kBtu/hr', 'W').get end water_heater_capacity_kbtu_per_hr = OpenStudio.convert(water_heater_capacity, 'W', 'kBtu/hr').get water_heater.setHeaterMaximumCapacity(water_heater_capacity) # default water heater volume if nil if water_heater_volume.nil? water_heater_volume = OpenStudio.convert(100.0, 'gal', 'm^3').get end water_heater_volume_gal = OpenStudio.convert(water_heater_volume, 'm^3', 'gal').get water_heater.setTankVolume(water_heater_volume) # set the water heater fuel case water_heater_fuel when 'Natural Gas', 'NaturalGas', 'Gas' water_heater.setHeaterFuelType('Gas') water_heater.setHeaterThermalEfficiency(0.78) water_heater.setOnCycleParasiticFuelConsumptionRate(on_cycle_parasitic_fuel_consumption_rate) water_heater.setOffCycleParasiticFuelConsumptionRate(off_cycle_parasitic_fuel_consumption_rate) water_heater.setOnCycleParasiticFuelType('Gas') water_heater.setOffCycleParasiticFuelType('Gas') water_heater.setOffCycleLossCoefficienttoAmbientTemperature(6.0) water_heater.setOnCycleLossCoefficienttoAmbientTemperature(6.0) when 'Electricity', 'Electric', 'Elec' water_heater.setHeaterFuelType('Electricity') water_heater.setHeaterThermalEfficiency(1.0) water_heater.setOnCycleParasiticFuelConsumptionRate(on_cycle_parasitic_fuel_consumption_rate) water_heater.setOffCycleParasiticFuelConsumptionRate(off_cycle_parasitic_fuel_consumption_rate) water_heater.setOnCycleParasiticFuelType('Electricity') water_heater.setOffCycleParasiticFuelType('Electricity') water_heater.setOffCycleLossCoefficienttoAmbientTemperature(1.053) water_heater.setOnCycleLossCoefficienttoAmbientTemperature(1.053) when 'FuelOilNo2' water_heater.setHeaterFuelType('FuelOilNo2') water_heater.setHeaterThermalEfficiency(0.78) water_heater.setOnCycleParasiticFuelConsumptionRate(on_cycle_parasitic_fuel_consumption_rate) water_heater.setOffCycleParasiticFuelConsumptionRate(off_cycle_parasitic_fuel_consumption_rate) water_heater.setOnCycleParasiticFuelType('FuelOilNo2') water_heater.setOffCycleParasiticFuelType('FuelOilNo2') water_heater.setOffCycleLossCoefficienttoAmbientTemperature(6.0) water_heater.setOnCycleLossCoefficienttoAmbientTemperature(6.0) when 'HeatPump', 'SimpleHeatPump' OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.ServiceWaterHeating', 'Simple workaround to represent heat pump water heaters without incurring significant runtime penalty associated with using correct objects.') # Make a part-load efficiency modifier curve with a value above 1, which is multiplied by the nominal efficiency of 100% to represent the COP of a HPWH. # @todo could make this workaround better by using EMS to modify this curve output in realtime based on the OA temperature. hpwh_cop = 2.8 water_heater.setHeaterFuelType('Electricity') water_heater.setHeaterThermalEfficiency(1.0) eff_f_of_plr = OpenStudio::Model::CurveCubic.new(model) eff_f_of_plr.setName("HPWH_COP_#{hpwh_cop}") eff_f_of_plr.setCoefficient1Constant(hpwh_cop) eff_f_of_plr.setCoefficient2x(0.0) eff_f_of_plr.setCoefficient3xPOW2(0.0) eff_f_of_plr.setCoefficient4xPOW3(0.0) eff_f_of_plr.setMinimumValueofx(0.0) eff_f_of_plr.setMaximumValueofx(1.0) water_heater.setPartLoadFactorCurve(eff_f_of_plr) water_heater.setOnCycleParasiticFuelConsumptionRate(on_cycle_parasitic_fuel_consumption_rate) water_heater.setOffCycleParasiticFuelConsumptionRate(off_cycle_parasitic_fuel_consumption_rate) water_heater.setOnCycleParasiticFuelType('Electricity') water_heater.setOffCycleParasiticFuelType('Electricity') water_heater.setOffCycleLossCoefficienttoAmbientTemperature(1.053) water_heater.setOnCycleLossCoefficienttoAmbientTemperature(1.053) else OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.ServiceWaterHeating', "#{water_heater_fuel} is not a valid water heater fuel. Valid choices are NaturalGas, Electricity, and HeatPump.") end # set water temperature properties water_heater.setDeadbandTemperatureDifference(2.0) water_heater.setDeadbandTemperatureDifference(OpenStudio.convert(3.6, 'R', 'K').get) water_heater.setHeaterControlType('Cycle') water_heater.setOffCycleParasiticHeatFractiontoTank(0.8) water_heater.setIndirectWaterHeatingRecoveryTime(1.5) # 1.5hrs # create service water temperature schedule based on the service_water_temperature if none provided if service_water_temperature_schedule.nil? swh_temp_c = service_water_temperature swh_temp_f = OpenStudio.convert(swh_temp_c, 'C', 'F').get service_water_temperature_schedule = OpenstudioStandards::Schedules.create_constant_schedule_ruleset(model, swh_temp_c, name: "Service Water Loop Temp - #{swh_temp_f.round}F", schedule_type_limit: 'Temperature') end water_heater.setMaximumTemperatureLimit(service_water_temperature) water_heater.setSetpointTemperatureSchedule(service_water_temperature_schedule) # set peak flow rate characteristics if set_peak_use_flowrate water_heater.setPeakUseFlowRate(peak_flowrate) unless peak_flowrate.nil? water_heater.setUseFlowRateFractionSchedule(flowrate_schedule) unless flowrate_schedule.nil? end # set the water heater ambient conditions if water_heater_thermal_zone.nil? # assume the water heater is indoors at 71.6F / 22C indoor_temp_f = 71.6 indoor_temp_c = OpenStudio.convert(indoor_temp_f, 'F', 'C').get default_water_heater_ambient_temp_sch = OpenstudioStandards::Schedules.create_constant_schedule_ruleset(model, indoor_temp_c, name: "Water Heater Ambient Temp Schedule #{indoor_temp_f}F", schedule_type_limit: 'Temperature') water_heater.setAmbientTemperatureIndicator('Schedule') water_heater.setAmbientTemperatureSchedule(default_water_heater_ambient_temp_sch) water_heater.resetAmbientTemperatureThermalZone else water_heater.setAmbientTemperatureIndicator('ThermalZone') water_heater.setAmbientTemperatureThermalZone(water_heater_thermal_zone) water_heater.resetAmbientTemperatureSchedule end # assign a quantity to the water heater if it represents multiple water heaters if number_of_water_heaters > 1 water_heater.setName("#{number_of_water_heaters}X #{(water_heater_volume_gal / number_of_water_heaters).round}gal #{water_heater_fuel} Water Heater - #{(water_heater_capacity_kbtu_per_hr / number_of_water_heaters).round}kBtu/hr") water_heater.additionalProperties.setFeature('component_quantity', number_of_water_heaters) else water_heater.setName("#{water_heater_volume_gal.round}gal #{water_heater_fuel} Water Heater - #{water_heater_capacity_kbtu_per_hr.round}kBtu/hr") end # add the water heater to the service water loop if provided unless service_water_loop.nil? service_water_loop.addSupplyBranchForComponent(water_heater) end OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ServiceWaterHeating', "Added water heater called #{water_heater.name}") return water_heater end |
.create_water_use(model, name: 'Main Water Use', flow_rate: 0.0, flow_rate_fraction_schedule: nil, water_use_temperature: 43.3, water_use_temperature_schedule: nil, sensible_fraction: 0.2, latent_fraction: 0.05, service_water_loop: nil, space: nil) ⇒ OpenStudio::Model::WaterUseEquipment
Creates a water use and attaches it to a service water loop and a space, if provided
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/openstudio-standards/service_water_heating/create_water_use.rb', line 21 def self.create_water_use(model, name: 'Main Water Use', flow_rate: 0.0, flow_rate_fraction_schedule: nil, water_use_temperature: 43.3, water_use_temperature_schedule: nil, sensible_fraction: 0.2, latent_fraction: 0.05, service_water_loop: nil, space: nil) # IP conversions for naming flow_rate_gpm = OpenStudio.convert(flow_rate, 'm^3/s', 'gal/min').get water_use_temperature_f = OpenStudio.convert(water_use_temperature, 'C', 'F').get # default name name = 'Main Water Use' if name.nil? # water use definition water_use_def = OpenStudio::Model::WaterUseEquipmentDefinition.new(model) # set sensible and latent fractions water_use_sensible_frac_sch = OpenstudioStandards::Schedules.create_constant_schedule_ruleset(model, sensible_fraction, name: "Fraction Sensible - #{sensible_fraction}", schedule_type_limit: 'Fractional') water_use_latent_frac_sch = OpenstudioStandards::Schedules.create_constant_schedule_ruleset(model, latent_fraction, name: "Fraction Latent - #{latent_fraction}", schedule_type_limit: 'Fractional') water_use_def.setSensibleFractionSchedule(water_use_sensible_frac_sch) water_use_def.setLatentFractionSchedule(water_use_latent_frac_sch) water_use_def.setPeakFlowRate(flow_rate) water_use_def.setName("#{name} #{flow_rate_gpm.round(2)}gpm #{water_use_temperature_f.round}F") # target mixed water temperature if water_use_temperature_schedule.nil? water_use_temperature_schedule = OpenstudioStandards::Schedules.create_constant_schedule_ruleset(model, water_use_temperature, name: "Mixed Water At Faucet Temp - #{water_use_temperature_f.round}F", schedule_type_limit: 'Temperature') end water_use_def.setTargetTemperatureSchedule(water_use_temperature_schedule) # create water use equipment water_fixture = OpenStudio::Model::WaterUseEquipment.new(water_use_def) water_fixture.setFlowRateFractionSchedule(flow_rate_fraction_schedule) # create water use connection swh_connection = OpenStudio::Model::WaterUseConnections.new(model) swh_connection.addWaterUseEquipment(water_fixture) # add to the space if provided if space.nil? water_fixture.setName("#{name} Service Water Use #{flow_rate_gpm.round(2)}gpm #{water_use_temperature_f.round}F") swh_connection.setName("#{name} WUC #{flow_rate_gpm.round(2)}gpm #{water_use_temperature_f.round}F") else water_fixture.setName("#{space.name} Service Water Use #{flow_rate_gpm.round(2)}gpm #{water_use_temperature_f.round}F") swh_connection.setName("#{space.name} WUC #{flow_rate_gpm.round(2)}gpm #{water_use_temperature_f.round}F") water_fixture.setSpace(space) end # add to the service water loop if provided unless service_water_loop.nil? service_water_loop.addDemandBranchForComponent(swh_connection) OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ServiceWaterHeating', "Adding water fixture to #{service_water_loop.name}.") end OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ServiceWaterHeating', "Added #{water_fixture.name}.") return water_fixture end |