honeybee-openstudio 2.30.5 → 2.31.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c093a7ba23305db86e618c8480375e646242ff00c18d51a68d1452a2811116ce
4
- data.tar.gz: 6fe7d668d07db8a0104d14f964e08b65b166bdffe66170bb88352d5390de1197
3
+ metadata.gz: e468a9bfb50550224bd130a49e06f492331f0d0770e7099e884454628da250f5
4
+ data.tar.gz: a7c066b0cd26e9193f3fbadc9687ae59f74a96dd24a3ecbb216fb64fc682509d
5
5
  SHA512:
6
- metadata.gz: 4014954666bee170a8cd83ff13468f907529fa4ddef7709cc307d9a1262f3eeb893487480697a897f5649dacc8eef5514c2d20e96b15a913c0129b32c3fc6005
7
- data.tar.gz: 8300e8718f8f28bbec2366935651cedc1bb145653dec3ea7cce508f4ca01c9117a49498101d5bc41fcc652ad848a8bc19ddb1b4c82e158113ae0e11dfeb2d112
6
+ metadata.gz: 7c02241cca2adcbce09295d25b9ddf9bf9aa684b0f08426924f2bc1564b84143fd4032dcdbcb24a9efe214dbfca16f5bfa424ddbe1d4b02ba5a1d769265028f5
7
+ data.tar.gz: 28f59d45b148e6a7be923e82834d796df8da4290ecebbb14371e756eca43e0ccb21f98512a59ac8eee53f7c19637a39abd2f9b9c0106e9bad07f13b05249e537
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = 'honeybee-openstudio'
7
- spec.version = '2.30.5'
7
+ spec.version = '2.31.0'
8
8
  spec.authors = ['Tanushree Charan', 'Dan Macumber', 'Chris Mackey', 'Mostapha Sadeghipour Roudsari']
9
9
  spec.email = ['tanushree.charan@nrel.gov', 'chris@ladybug.tools']
10
10
 
@@ -3,7 +3,7 @@
3
3
  "servers": [],
4
4
  "info": {
5
5
  "description": "Honeybee model schema.",
6
- "version": "1.48.1",
6
+ "version": "1.48.2",
7
7
  "title": "Honeybee Model Schema",
8
8
  "contact": {
9
9
  "name": "Ladybug Tools",
@@ -574,6 +574,31 @@
574
574
  "x-displayName": "RadianceSubFaceStateAbridged",
575
575
  "description": "<SchemaDefinition schemaRef=\"#/components/schemas/RadianceSubFaceStateAbridged\" />\n"
576
576
  },
577
+ {
578
+ "name": "radiant_model",
579
+ "x-displayName": "Radiant",
580
+ "description": "<SchemaDefinition schemaRef=\"#/components/schemas/Radiant\" />\n"
581
+ },
582
+ {
583
+ "name": "radiantequipmenttype_model",
584
+ "x-displayName": "RadiantEquipmentType",
585
+ "description": "<SchemaDefinition schemaRef=\"#/components/schemas/RadiantEquipmentType\" />\n"
586
+ },
587
+ {
588
+ "name": "radiantfacetypes_model",
589
+ "x-displayName": "RadiantFaceTypes",
590
+ "description": "<SchemaDefinition schemaRef=\"#/components/schemas/RadiantFaceTypes\" />\n"
591
+ },
592
+ {
593
+ "name": "radiantwithdoasabridged_model",
594
+ "x-displayName": "RadiantwithDOASAbridged",
595
+ "description": "<SchemaDefinition schemaRef=\"#/components/schemas/RadiantwithDOASAbridged\" />\n"
596
+ },
597
+ {
598
+ "name": "radiantwithdoasequipmenttype_model",
599
+ "x-displayName": "RadiantwithDOASEquipmentType",
600
+ "description": "<SchemaDefinition schemaRef=\"#/components/schemas/RadiantwithDOASEquipmentType\" />\n"
601
+ },
577
602
  {
578
603
  "name": "residential_model",
579
604
  "x-displayName": "Residential",
@@ -1054,6 +1079,11 @@
1054
1079
  "pvavequipmenttype_model",
1055
1080
  "radianceshadestateabridged_model",
1056
1081
  "radiancesubfacestateabridged_model",
1082
+ "radiant_model",
1083
+ "radiantequipmenttype_model",
1084
+ "radiantfacetypes_model",
1085
+ "radiantwithdoasabridged_model",
1086
+ "radiantwithdoasequipmenttype_model",
1057
1087
  "residential_model",
1058
1088
  "residentialequipmenttype_model",
1059
1089
  "roofceilingconstructionset_model",
@@ -8199,6 +8229,151 @@
8199
8229
  ],
8200
8230
  "additionalProperties": false
8201
8231
  },
8232
+ "RadiantwithDOASEquipmentType": {
8233
+ "title": "RadiantwithDOASEquipmentType",
8234
+ "description": "An enumeration.",
8235
+ "enum": [
8236
+ "DOAS_Radiant_Chiller_Boiler",
8237
+ "DOAS_Radiant_Chiller_ASHP",
8238
+ "DOAS_Radiant_Chiller_DHW",
8239
+ "DOAS_Radiant_ACChiller_Boiler",
8240
+ "DOAS_Radiant_ACChiller_ASHP",
8241
+ "DOAS_Radiant_ACChiller_DHW",
8242
+ "DOAS_Radiant_DCW_Boiler",
8243
+ "DOAS_Radiant_DCW_ASHP",
8244
+ "DOAS_Radiant_DCW_DHW"
8245
+ ],
8246
+ "type": "string"
8247
+ },
8248
+ "RadiantFaceTypes": {
8249
+ "title": "RadiantFaceTypes",
8250
+ "description": "An enumeration.",
8251
+ "enum": [
8252
+ "Floor",
8253
+ "Ceiling",
8254
+ "FloorWithCarpet"
8255
+ ],
8256
+ "type": "string"
8257
+ },
8258
+ "RadiantwithDOASAbridged": {
8259
+ "title": "RadiantwithDOASAbridged",
8260
+ "description": "Low Temperature Radiant with DOAS HVAC system.",
8261
+ "type": "object",
8262
+ "properties": {
8263
+ "identifier": {
8264
+ "title": "Identifier",
8265
+ "description": "Text string for a unique object ID. This identifier remains constant as the object is mutated, copied, and serialized to different formats (eg. dict, idf, osm). This identifier is also used to reference the object across a Model. It must be < 100 characters, use only ASCII characters and exclude (, ; ! \\n \\t).",
8266
+ "maxLength": 100,
8267
+ "minLength": 1,
8268
+ "pattern": "^[^,;!\\n\\t]+$",
8269
+ "type": "string"
8270
+ },
8271
+ "display_name": {
8272
+ "title": "Display Name",
8273
+ "description": "Display name of the object with no character restrictions.",
8274
+ "type": "string"
8275
+ },
8276
+ "user_data": {
8277
+ "title": "User Data",
8278
+ "description": "Optional dictionary of user data associated with the object.All keys and values of this dictionary should be of a standard data type to ensure correct serialization of the object (eg. str, float, int, list).",
8279
+ "type": "object"
8280
+ },
8281
+ "vintage": {
8282
+ "description": "Text for the vintage of the template system. This will be used to set efficiencies for various pieces of equipment within the system. Further information about these defaults can be found in the version of ASHRAE 90.1 corresponding to the selected vintage. Read-only versions of the standard can be found at: https://www.ashrae.org/technical-resources/standards-and-guidelines/read-only-versions-of-ashrae-standards",
8283
+ "default": "ASHRAE_2019",
8284
+ "allOf": [
8285
+ {
8286
+ "$ref": "#/components/schemas/Vintages"
8287
+ }
8288
+ ]
8289
+ },
8290
+ "sensible_heat_recovery": {
8291
+ "title": "Sensible Heat Recovery",
8292
+ "description": "A number between 0 and 1 for the effectiveness of sensible heat recovery within the system.",
8293
+ "default": 0,
8294
+ "minimum": 0,
8295
+ "maximum": 1,
8296
+ "type": "number",
8297
+ "format": "double"
8298
+ },
8299
+ "latent_heat_recovery": {
8300
+ "title": "Latent Heat Recovery",
8301
+ "description": "A number between 0 and 1 for the effectiveness of latent heat recovery within the system.",
8302
+ "default": 0,
8303
+ "minimum": 0,
8304
+ "maximum": 1,
8305
+ "type": "number",
8306
+ "format": "double"
8307
+ },
8308
+ "demand_controlled_ventilation": {
8309
+ "title": "Demand Controlled Ventilation",
8310
+ "description": "Boolean to note whether demand controlled ventilation should be used on the system, which will vary the amount of ventilation air according to the occupancy schedule of the Rooms.",
8311
+ "default": false,
8312
+ "type": "boolean"
8313
+ },
8314
+ "doas_availability_schedule": {
8315
+ "title": "Doas Availability Schedule",
8316
+ "description": "An optional On/Off discrete schedule to set when the dedicated outdoor air system (DOAS) shuts off. This will not only prevent any outdoor air from flowing thorough the system but will also shut off the fans, which can result in more energy savings when spaces served by the DOAS are completely unoccupied. If None, the DOAS will be always on.",
8317
+ "maxLength": 100,
8318
+ "minLength": 1,
8319
+ "type": "string"
8320
+ },
8321
+ "type": {
8322
+ "title": "Type",
8323
+ "default": "RadiantwithDOASAbridged",
8324
+ "pattern": "^RadiantwithDOASAbridged$",
8325
+ "type": "string",
8326
+ "readOnly": true
8327
+ },
8328
+ "equipment_type": {
8329
+ "description": "Text for the specific type of system equipment from the RadiantwithDOASEquipmentType enumeration.",
8330
+ "default": "DOAS_Radiant_Chiller_Boiler",
8331
+ "allOf": [
8332
+ {
8333
+ "$ref": "#/components/schemas/RadiantwithDOASEquipmentType"
8334
+ }
8335
+ ]
8336
+ },
8337
+ "proportional_gain": {
8338
+ "title": "Proportional Gain",
8339
+ "description": "A fractional number for the proportional gain constant. Recommended values are 0.3 or less.",
8340
+ "default": 0.3,
8341
+ "minimum": 0,
8342
+ "maximum": 1,
8343
+ "type": "number",
8344
+ "format": "double"
8345
+ },
8346
+ "minimum_operation_time": {
8347
+ "title": "Minimum Operation Time",
8348
+ "description": "A number for the minimum number of hours of operation for the radiant system before it shuts off.",
8349
+ "default": 1.0,
8350
+ "exclusiveMinimum": 0,
8351
+ "type": "number",
8352
+ "format": "double"
8353
+ },
8354
+ "switch_over_time": {
8355
+ "title": "Switch Over Time",
8356
+ "description": "A number for the minimum number of hours for when the system can switch between heating and cooling.",
8357
+ "default": 24.0,
8358
+ "exclusiveMinimum": 0,
8359
+ "type": "number",
8360
+ "format": "double"
8361
+ },
8362
+ "radiant_face_type": {
8363
+ "description": "Text to indicate which faces are thermally active by default. Note that this property has no effect when the rooms to which the HVAC system is assigned have constructions with internal source materials. In this case, those constructions will dictate the thermally active surfaces.",
8364
+ "default": "Floor",
8365
+ "allOf": [
8366
+ {
8367
+ "$ref": "#/components/schemas/RadiantFaceTypes"
8368
+ }
8369
+ ]
8370
+ }
8371
+ },
8372
+ "required": [
8373
+ "identifier"
8374
+ ],
8375
+ "additionalProperties": false
8376
+ },
8202
8377
  "FCUEquipmentType": {
8203
8378
  "title": "FCUEquipmentType",
8204
8379
  "description": "An enumeration.",
@@ -8738,6 +8913,110 @@
8738
8913
  ],
8739
8914
  "additionalProperties": false
8740
8915
  },
8916
+ "RadiantEquipmentType": {
8917
+ "title": "RadiantEquipmentType",
8918
+ "description": "An enumeration.",
8919
+ "enum": [
8920
+ "Radiant_Chiller_Boiler",
8921
+ "Radiant_Chiller_ASHP",
8922
+ "Radiant_Chiller_DHW",
8923
+ "Radiant_ACChiller_Boiler",
8924
+ "Radiant_ACChiller_ASHP",
8925
+ "Radiant_ACChiller_DHW",
8926
+ "Radiant_DCW_Boiler",
8927
+ "Radiant_DCW_ASHP",
8928
+ "Radiant_DCW_DHW"
8929
+ ],
8930
+ "type": "string"
8931
+ },
8932
+ "Radiant": {
8933
+ "title": "Radiant",
8934
+ "description": "Low Temperature Radiant system.",
8935
+ "type": "object",
8936
+ "properties": {
8937
+ "identifier": {
8938
+ "title": "Identifier",
8939
+ "description": "Text string for a unique object ID. This identifier remains constant as the object is mutated, copied, and serialized to different formats (eg. dict, idf, osm). This identifier is also used to reference the object across a Model. It must be < 100 characters, use only ASCII characters and exclude (, ; ! \\n \\t).",
8940
+ "maxLength": 100,
8941
+ "minLength": 1,
8942
+ "pattern": "^[^,;!\\n\\t]+$",
8943
+ "type": "string"
8944
+ },
8945
+ "display_name": {
8946
+ "title": "Display Name",
8947
+ "description": "Display name of the object with no character restrictions.",
8948
+ "type": "string"
8949
+ },
8950
+ "user_data": {
8951
+ "title": "User Data",
8952
+ "description": "Optional dictionary of user data associated with the object.All keys and values of this dictionary should be of a standard data type to ensure correct serialization of the object (eg. str, float, int, list).",
8953
+ "type": "object"
8954
+ },
8955
+ "vintage": {
8956
+ "description": "Text for the vintage of the template system. This will be used to set efficiencies for various pieces of equipment within the system. Further information about these defaults can be found in the version of ASHRAE 90.1 corresponding to the selected vintage. Read-only versions of the standard can be found at: https://www.ashrae.org/technical-resources/standards-and-guidelines/read-only-versions-of-ashrae-standards",
8957
+ "default": "ASHRAE_2019",
8958
+ "allOf": [
8959
+ {
8960
+ "$ref": "#/components/schemas/Vintages"
8961
+ }
8962
+ ]
8963
+ },
8964
+ "type": {
8965
+ "title": "Type",
8966
+ "default": "Radiant",
8967
+ "pattern": "^Radiant$",
8968
+ "type": "string",
8969
+ "readOnly": true
8970
+ },
8971
+ "equipment_type": {
8972
+ "description": "Text for the specific type of system equipment from the RadiantEquipmentType enumeration.",
8973
+ "default": "Radiant_Chiller_Boiler",
8974
+ "allOf": [
8975
+ {
8976
+ "$ref": "#/components/schemas/RadiantEquipmentType"
8977
+ }
8978
+ ]
8979
+ },
8980
+ "proportional_gain": {
8981
+ "title": "Proportional Gain",
8982
+ "description": "A fractional number for the proportional gain constant. Recommended values are 0.3 or less.",
8983
+ "default": 0.3,
8984
+ "minimum": 0,
8985
+ "maximum": 1,
8986
+ "type": "number",
8987
+ "format": "double"
8988
+ },
8989
+ "minimum_operation_time": {
8990
+ "title": "Minimum Operation Time",
8991
+ "description": "A number for the minimum number of hours of operation for the radiant system before it shuts off.",
8992
+ "default": 1.0,
8993
+ "exclusiveMinimum": 0,
8994
+ "type": "number",
8995
+ "format": "double"
8996
+ },
8997
+ "switch_over_time": {
8998
+ "title": "Switch Over Time",
8999
+ "description": "A number for the minimum number of hours for when the system can switch between heating and cooling.",
9000
+ "default": 24.0,
9001
+ "exclusiveMinimum": 0,
9002
+ "type": "number",
9003
+ "format": "double"
9004
+ },
9005
+ "radiant_face_type": {
9006
+ "description": "Text to indicate which faces are thermally active by default. Note that this property has no effect when the rooms to which the HVAC system is assigned have constructions with internal source materials. In this case, those constructions will dictate the thermally active surfaces.",
9007
+ "default": "Floor",
9008
+ "allOf": [
9009
+ {
9010
+ "$ref": "#/components/schemas/RadiantFaceTypes"
9011
+ }
9012
+ ]
9013
+ }
9014
+ },
9015
+ "required": [
9016
+ "identifier"
9017
+ ],
9018
+ "additionalProperties": false
9019
+ },
8741
9020
  "SHWEquipmentType": {
8742
9021
  "title": "SHWEquipmentType",
8743
9022
  "description": "An enumeration.",
@@ -10575,6 +10854,9 @@
10575
10854
  {
10576
10855
  "$ref": "#/components/schemas/VRFwithDOASAbridged"
10577
10856
  },
10857
+ {
10858
+ "$ref": "#/components/schemas/RadiantwithDOASAbridged"
10859
+ },
10578
10860
  {
10579
10861
  "$ref": "#/components/schemas/FCU"
10580
10862
  },
@@ -10598,6 +10880,9 @@
10598
10880
  },
10599
10881
  {
10600
10882
  "$ref": "#/components/schemas/GasUnitHeater"
10883
+ },
10884
+ {
10885
+ "$ref": "#/components/schemas/Radiant"
10601
10886
  }
10602
10887
  ]
10603
10888
  }
@@ -13833,7 +14118,7 @@
13833
14118
  "version": {
13834
14119
  "title": "Version",
13835
14120
  "description": "Text string for the current version of the schema.",
13836
- "default": "1.48.1",
14121
+ "default": "1.48.2",
13837
14122
  "pattern": "([0-9]+)\\.([0-9]+)\\.([0-9]+)",
13838
14123
  "type": "string",
13839
14124
  "readOnly": true
@@ -36,9 +36,10 @@ module Honeybee
36
36
  attr_reader :errors, :warnings
37
37
 
38
38
  @@all_air_types = ['VAV', 'PVAV', 'PSZ', 'PTAC', 'ForcedAirFurnace']
39
- @@doas_types = ['FCUwithDOASAbridged', 'WSHPwithDOASAbridged', 'VRFwithDOASAbridged']
39
+ @@doas_types = ['FCUwithDOASAbridged', 'WSHPwithDOASAbridged',
40
+ 'VRFwithDOASAbridged', 'RadiantwithDOASAbridged']
40
41
  @@heat_cool_types = ['FCU', 'WSHP', 'VRF', 'Baseboard', 'EvaporativeCooler',
41
- 'Residential', 'WindowAC', 'GasUnitHeater']
42
+ 'Residential', 'WindowAC', 'GasUnitHeater', 'Radiant']
42
43
  @@types = @@all_air_types + @@doas_types + @@heat_cool_types
43
44
 
44
45
  def allowable_types
@@ -29,9 +29,10 @@
29
29
  # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
30
  # *******************************************************************************
31
31
 
32
- # Note: This file is copied directly from the "Create Typical DOE Building from Model" measure
32
+ # Note: This file is copied from the "Create Typical DOE Building from Model" measure
33
33
  # https://bcl.nrel.gov/node/85019
34
- # It is intended that this file be re-copied if new system types are added
34
+ # https://github.com/NREL/openstudio-model-articulation-gem/tree/develop/lib/measures/create_typical_doe_building_from_model
35
+ # It is intended that this file be updated if new system types are added to the original file
35
36
 
36
37
  class OpenStudio::Model::Model
37
38
  # Adds the HVAC system as derived from the combinations of CBECS 2012 MAINHT and MAINCL fields.
@@ -49,7 +50,7 @@ class OpenStudio::Model::Model
49
50
  system_zones = heated_and_cooled_zones + cooled_only_zones
50
51
 
51
52
  # system type naming convention:
52
- # [ventilation strategy] [ cooling system and plant] [heating system and plant]
53
+ # [ventilation strategy] [cooling system and plant] [heating system and plant]
53
54
 
54
55
  case system_type
55
56
 
@@ -0,0 +1,164 @@
1
+ # *******************************************************************************
2
+ # Honeybee OpenStudio Gem, Copyright (c) 2020, Alliance for Sustainable
3
+ # Energy, LLC, Ladybug Tools LLC and other contributors. All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # (1) Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ #
11
+ # (2) Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # (3) Neither the name of the copyright holder nor the names of any contributors
16
+ # may be used to endorse or promote products derived from this software without
17
+ # specific prior written permission from the respective party.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
20
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
23
+ # UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
24
+ # THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
+ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
+ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+ # *******************************************************************************
31
+
32
+ # Note: This file is derived from the "Radiant Slab with DOAS" measure
33
+ # https://github.com/NREL/openstudio-model-articulation-gem/tree/develop/lib/measures/radiant_slab_with_doas
34
+ # It is intended that this file be updated if changes are made to the original measure
35
+
36
+ class OpenStudio::Model::Model
37
+ # Adds a radiant HVAC system to the model
38
+ def add_radiant_hvac_system(std, system_type, zones, rad_props)
39
+ # the 'zones' argument includes zones that have heating, cooling, or both
40
+ conditioned_zones = zones.select { |zone| std.thermal_zone_heated?(zone) && std.thermal_zone_cooled?(zone) }
41
+
42
+ # get the climate zone from the model, which will help set water temerpatures
43
+ climate_zone_obj = self.getClimateZones.getClimateZone('ASHRAE', 2006)
44
+ if climate_zone_obj.empty
45
+ climate_zone_obj = self.getClimateZones.getClimateZone('ASHRAE', 2013)
46
+ end
47
+ if climate_zone_obj.empty || climate_zone_obj.value == ''
48
+ climate_zone = ''
49
+ else
50
+ climate_zone = climate_zone_obj.value
51
+ end
52
+
53
+ # get the radiant hot water temperature based on the climate zone
54
+ case climate_zone
55
+ when '0', '1'
56
+ radiant_htg_dsgn_sup_wtr_temp_f = 90.0
57
+ when '2', '2A', '2B'
58
+ radiant_htg_dsgn_sup_wtr_temp_f = 100.0
59
+ when '3', '3A', '3B', '3C'
60
+ radiant_htg_dsgn_sup_wtr_temp_f = 100.0
61
+ when '4', '4A', '4B', '4C'
62
+ radiant_htg_dsgn_sup_wtr_temp_f = 100.0
63
+ when '5', '5A', '5B', '5C'
64
+ radiant_htg_dsgn_sup_wtr_temp_f = 110.0
65
+ when '6', '6A', '6B'
66
+ radiant_htg_dsgn_sup_wtr_temp_f = 120.0
67
+ when '7', '8'
68
+ radiant_htg_dsgn_sup_wtr_temp_f = 120.0
69
+ else # unrecognized climate zone; default to climate zone 4
70
+ radiant_htg_dsgn_sup_wtr_temp_f = 100.0
71
+ end
72
+
73
+ # create the hot water loop
74
+ if system_type.include? 'ASHP'
75
+ boiler_fuel_type = 'ASHP'
76
+ elsif system_type.include? 'Boiler'
77
+ boiler_fuel_type = 'NaturalGas'
78
+ elsif system_type.include? 'DHW'
79
+ boiler_fuel_type = 'DistrictHeating'
80
+ end
81
+ hot_water_loop = std.model_add_hw_loop(
82
+ self,
83
+ boiler_fuel_type,
84
+ dsgn_sup_wtr_temp: radiant_htg_dsgn_sup_wtr_temp_f,
85
+ dsgn_sup_wtr_temp_delt: 10.0)
86
+
87
+ # create the chilled water loop
88
+ if system_type.include? 'Radiant_Chiller' # water-cooled chiller
89
+ # make condenser water loop
90
+ fan_type = std.model_cw_loop_cooling_tower_fan_type(self)
91
+ condenser_water_loop = std.model_add_cw_loop(
92
+ self,
93
+ cooling_tower_type: 'Open Cooling Tower',
94
+ cooling_tower_fan_type: 'Propeller or Axial',
95
+ cooling_tower_capacity_control: fan_type,
96
+ number_of_cells_per_tower: 1,
97
+ number_cooling_towers: 1)
98
+ # make chilled water loop
99
+ chilled_water_loop = std.model_add_chw_loop(
100
+ self,
101
+ chw_pumping_type: 'const_pri_var_sec',
102
+ dsgn_sup_wtr_temp: 55.0,
103
+ dsgn_sup_wtr_temp_delt: 5.0,
104
+ chiller_cooling_type: 'WaterCooled',
105
+ condenser_water_loop: condenser_water_loop)
106
+ elsif system_type.include? 'Radiant_ACChiller' # air-cooled chiller
107
+ chilled_water_loop = std.model_add_chw_loop(
108
+ self,
109
+ chw_pumping_type: 'const_pri_var_sec',
110
+ dsgn_sup_wtr_temp: 55.0,
111
+ dsgn_sup_wtr_temp_delt: 5.0,
112
+ chiller_cooling_type: 'AirCooled')
113
+ else # district chilled water cooled
114
+ chilled_water_loop = std.model_add_chw_loop(
115
+ self,
116
+ cooling_fuel: 'DistrictCooling',
117
+ chw_pumping_type: 'const_pri_var_sec',
118
+ dsgn_sup_wtr_temp: 55.0,
119
+ dsgn_sup_wtr_temp_delt: 5.0)
120
+ end
121
+
122
+ # get the various controls for the radiant system
123
+ if rad_props[:proportional_gain]
124
+ proportional_gain = rad_props[:proportional_gain]
125
+ else
126
+ proportional_gain = 0.3
127
+ end
128
+ if rad_props[:minimum_operation_time]
129
+ minimum_operation = rad_props[:minimum_operation_time]
130
+ else
131
+ minimum_operation = 1
132
+ end
133
+ if rad_props[:switch_over_time]
134
+ switch_over_time = rad_props[:switch_over_time]
135
+ else
136
+ switch_over_time = 24
137
+ end
138
+
139
+ # add radiant system to the conditioned zones
140
+ include_carpet = false
141
+ if rad_props[:radiant_face_type]
142
+ radiant_type = rad_props[:radiant_face_type].downcase
143
+ if radiant_type == 'floorwithcarpet'
144
+ radiant_type = 'floor'
145
+ include_carpet = true
146
+ end
147
+ else
148
+ radiant_type = 'floor'
149
+ end
150
+ radiant_loops = std.model_add_low_temp_radiant(
151
+ self, conditioned_zones, hot_water_loop, chilled_water_loop,
152
+ radiant_type: radiant_type,
153
+ include_carpet: include_carpet,
154
+ proportional_gain: proportional_gain,
155
+ minimum_operation: minimum_operation,
156
+ switch_over_time: switch_over_time)
157
+
158
+ # if the equipment includes a DOAS, then add it
159
+ if system_type.include? 'DOAS_'
160
+ std.model_add_doas(self, conditioned_zones)
161
+ end
162
+
163
+ end
164
+ end
@@ -51,6 +51,7 @@ module Honeybee
51
51
  # only load openstudio-standards when needed
52
52
  require 'openstudio-standards'
53
53
  require_relative 'Model.hvac'
54
+ require_relative 'radiant'
54
55
 
55
56
  # get the defaults for the specific system type
56
57
  hvac_defaults = defaults(@hash[:type])
@@ -79,120 +80,139 @@ module Honeybee
79
80
  end
80
81
  end
81
82
 
82
- # create the HVAC system and assign the display name to the air loop name if it exists
83
- os_hvac = openstudio_model.add_cbecs_hvac_system(standard, equipment_type, zones)
84
- os_air_loop = nil
83
+ # create the HVAC system
84
+ if equipment_type.to_s.include? 'Radiant'
85
+ os_hvac = openstudio_model.add_radiant_hvac_system(standard, equipment_type.to_s, zones, @hash)
86
+ else
87
+ os_hvac = openstudio_model.add_cbecs_hvac_system(standard, equipment_type, zones)
88
+ end
89
+
90
+ # Get the air loops and assign the display name to the air loop name if it exists
91
+ os_air_loops = []
85
92
  air_loops = openstudio_model.getAirLoopHVACs
86
93
  unless air_loops.length == $air_loop_count # check if any new loops were added
87
94
  $air_loop_count = air_loops.length
88
- os_air_terminal = []
89
95
  zones.each do |zon|
90
96
  os_air_terminal = zon.airLoopHVACTerminal
91
- break if !os_air_terminal.empty?
92
- end
93
- unless os_air_terminal.empty?
94
- os_air_terminal = os_air_terminal.get
95
- os_air_loop_opt = os_air_terminal.airLoopHVAC
96
- unless os_air_loop_opt.empty?
97
- os_air_loop = os_air_loop_opt.get
98
- loop_name = os_air_loop.name
99
- unless loop_name.empty?
100
- # set the name of the air loop to align with the HVAC name
101
- if @hash[:display_name]
102
- clean_name = @hash[:display_name].to_s.gsub(/[^.A-Za-z0-9_-] /, " ")
103
- os_air_loop.setName(clean_name + ' - ' + loop_name.get)
97
+ unless os_air_terminal.empty?
98
+ os_air_terminal = os_air_terminal.get
99
+ os_air_loop_opt = os_air_terminal.airLoopHVAC
100
+ unless os_air_loop_opt.empty?
101
+ os_air_loop = os_air_loop_opt.get
102
+ os_air_loops << os_air_loop
103
+ loop_name = os_air_loop.name
104
+ unless loop_name.empty?
105
+ # set the name of the air loop to align with the HVAC name
106
+ if @hash[:display_name]
107
+ clean_name = @hash[:display_name].to_s.gsub(/[^.A-Za-z0-9_-] /, " ")
108
+ os_air_loop.setName(clean_name + ' - ' + loop_name.get)
109
+ end
104
110
  end
111
+ break if !equipment_type.include? 'PSZ' # multiple air loops have been added
105
112
  end
106
113
  end
107
114
  end
108
115
  end
109
116
 
110
117
  # assign the economizer type if there's an air loop and the economizer is specified
111
- if @hash[:economizer_type] && os_air_loop
112
- oasys = os_air_loop.airLoopHVACOutdoorAirSystem
113
- unless oasys.empty?
114
- os_oasys = oasys.get
115
- oactrl = os_oasys.getControllerOutdoorAir
116
- oactrl.setEconomizerControlType(@hash[:economizer_type])
118
+ if @hash[:economizer_type] && !os_air_loops.empty?
119
+ os_air_loops.each do |os_air_loop|
120
+ oasys = os_air_loop.airLoopHVACOutdoorAirSystem
121
+ unless oasys.empty?
122
+ os_oasys = oasys.get
123
+ oactrl = os_oasys.getControllerOutdoorAir
124
+ oactrl.setEconomizerControlType(@hash[:economizer_type])
125
+ end
117
126
  end
118
127
  end
119
128
 
120
129
  # set the sensible heat recovery if there's an air loop and the heat recovery is specified
121
- if @hash[:sensible_heat_recovery] && @hash[:sensible_heat_recovery] != 0 && os_air_loop
122
- erv = get_existing_erv(os_air_loop)
123
- unless erv
124
- erv = create_erv(openstudio_model, os_air_loop)
130
+ if @hash[:sensible_heat_recovery] && @hash[:sensible_heat_recovery] != 0 && !os_air_loops.empty?
131
+ os_air_loops.each do |os_air_loop|
132
+ erv = get_existing_erv(os_air_loop)
133
+ unless erv
134
+ erv = create_erv(openstudio_model, os_air_loop)
135
+ end
136
+ eff_at_max = @hash[:sensible_heat_recovery] * (0.76 / 0.81) # taken from OpenStudio defaults
137
+ erv.setSensibleEffectivenessat100CoolingAirFlow(eff_at_max)
138
+ erv.setSensibleEffectivenessat100HeatingAirFlow(eff_at_max)
139
+ erv.setSensibleEffectivenessat75CoolingAirFlow(@hash[:sensible_heat_recovery])
140
+ erv.setSensibleEffectivenessat75HeatingAirFlow(@hash[:sensible_heat_recovery])
125
141
  end
126
- eff_at_max = @hash[:sensible_heat_recovery] * (0.76 / 0.81) # taken from OpenStudio defaults
127
- erv.setSensibleEffectivenessat100CoolingAirFlow(eff_at_max)
128
- erv.setSensibleEffectivenessat100HeatingAirFlow(eff_at_max)
129
- erv.setSensibleEffectivenessat75CoolingAirFlow(@hash[:sensible_heat_recovery])
130
- erv.setSensibleEffectivenessat75HeatingAirFlow(@hash[:sensible_heat_recovery])
131
142
  end
132
143
 
133
144
  # set the latent heat recovery if there's an air loop and the heat recovery is specified
134
- if @hash[:latent_heat_recovery] && @hash[:latent_heat_recovery] != 0 && os_air_loop
135
- erv = get_existing_erv(os_air_loop)
136
- unless erv
137
- erv = create_erv(openstudio_model, os_air_loop)
145
+ if @hash[:latent_heat_recovery] && @hash[:latent_heat_recovery] != 0 && !os_air_loops.empty?
146
+ os_air_loops.each do |os_air_loop|
147
+ erv = get_existing_erv(os_air_loop)
148
+ unless erv
149
+ erv = create_erv(openstudio_model, os_air_loop)
150
+ end
151
+ eff_at_max = @hash[:latent_heat_recovery] * (0.68 / 0.73) # taken from OpenStudio defaults
152
+ erv.setLatentEffectivenessat100CoolingAirFlow(eff_at_max)
153
+ erv.setLatentEffectivenessat100HeatingAirFlow(eff_at_max)
154
+ erv.setLatentEffectivenessat75CoolingAirFlow(@hash[:latent_heat_recovery])
155
+ erv.setLatentEffectivenessat75HeatingAirFlow(@hash[:latent_heat_recovery])
138
156
  end
139
- eff_at_max = @hash[:latent_heat_recovery] * (0.68 / 0.73) # taken from OpenStudio defaults
140
- erv.setLatentEffectivenessat100CoolingAirFlow(eff_at_max)
141
- erv.setLatentEffectivenessat100HeatingAirFlow(eff_at_max)
142
- erv.setLatentEffectivenessat75CoolingAirFlow(@hash[:latent_heat_recovery])
143
- erv.setLatentEffectivenessat75HeatingAirFlow(@hash[:latent_heat_recovery])
144
157
  end
145
158
 
146
159
  # assign demand controlled ventilation if there's an air loop
147
- if @hash[:demand_controlled_ventilation] && os_air_loop
148
- oasys = os_air_loop.airLoopHVACOutdoorAirSystem
149
- unless oasys.empty?
150
- os_oasys = oasys.get
151
- oactrl = os_oasys.getControllerOutdoorAir
152
- vent_ctrl = oactrl.controllerMechanicalVentilation
153
- vent_ctrl.setDemandControlledVentilationNoFail(true)
154
- oactrl.resetMinimumFractionofOutdoorAirSchedule
160
+ if @hash[:demand_controlled_ventilation] && !os_air_loops.empty?
161
+ os_air_loops.each do |os_air_loop|
162
+ oasys = os_air_loop.airLoopHVACOutdoorAirSystem
163
+ unless oasys.empty?
164
+ os_oasys = oasys.get
165
+ oactrl = os_oasys.getControllerOutdoorAir
166
+ vent_ctrl = oactrl.controllerMechanicalVentilation
167
+ vent_ctrl.setDemandControlledVentilationNoFail(true)
168
+ oactrl.resetMinimumFractionofOutdoorAirSchedule
169
+ end
155
170
  end
156
171
  end
157
172
 
158
173
  # assign the DOAS availability schedule if there's an air loop and it is specified
159
- if @hash[:doas_availability_schedule] && os_air_loop
160
- schedule = openstudio_model.getScheduleByName(@hash[:doas_availability_schedule])
161
- unless schedule.empty?
162
- avail_sch = schedule.get
163
- os_air_loop.setAvailabilitySchedule(avail_sch)
174
+ if @hash[:doas_availability_schedule] && !os_air_loops.empty?
175
+ os_air_loops.each do |os_air_loop|
176
+ schedule = openstudio_model.getScheduleByName(@hash[:doas_availability_schedule])
177
+ unless schedule.empty?
178
+ avail_sch = schedule.get
179
+ os_air_loop.setAvailabilitySchedule(avail_sch)
180
+ end
164
181
  end
165
182
  end
166
183
 
167
184
  # set the outdoor air controller to respect room-level ventilation schedules if they exist
168
- if os_air_loop
169
- oasys = os_air_loop.airLoopHVACOutdoorAirSystem
170
- unless oasys.empty?
171
- os_oasys = oasys.get
172
- oactrl = os_oasys.getControllerOutdoorAir
173
- oa_sch, oa_sch_name = nil, nil
174
- zones.each do |zone|
175
- oa_spec = zone.spaces[0].designSpecificationOutdoorAir
176
- unless oa_spec.empty?
177
- oa_spec = oa_spec.get
178
- space_oa_sch = oa_spec.outdoorAirFlowRateFractionSchedule
179
- unless space_oa_sch.empty?
180
- space_oa_sch = space_oa_sch.get
181
- space_oa_sch_name = space_oa_sch.name
182
- unless space_oa_sch_name.empty?
183
- space_oa_sch_name = space_oa_sch_name.get
184
- if oa_sch_name.nil? || space_oa_sch_name == oa_sch_name
185
- oa_sch, oa_sch_name = space_oa_sch, space_oa_sch_name
186
- else
187
- oa_sch = nil
188
- end
185
+ if !os_air_loops.empty?
186
+ oa_sch, oa_sch_name = nil, nil
187
+ zones.each do |zone|
188
+ oa_spec = zone.spaces[0].designSpecificationOutdoorAir
189
+ unless oa_spec.empty?
190
+ oa_spec = oa_spec.get
191
+ space_oa_sch = oa_spec.outdoorAirFlowRateFractionSchedule
192
+ unless space_oa_sch.empty?
193
+ space_oa_sch = space_oa_sch.get
194
+ space_oa_sch_name = space_oa_sch.name
195
+ unless space_oa_sch_name.empty?
196
+ space_oa_sch_name = space_oa_sch_name.get
197
+ if oa_sch_name.nil? || space_oa_sch_name == oa_sch_name
198
+ oa_sch, oa_sch_name = space_oa_sch, space_oa_sch_name
199
+ else
200
+ oa_sch = nil
189
201
  end
190
202
  end
191
203
  end
192
204
  end
193
- if oa_sch
194
- oactrl.resetMinimumFractionofOutdoorAirSchedule
195
- oactrl.setMinimumOutdoorAirSchedule(oa_sch)
205
+ end
206
+
207
+ if oa_sch
208
+ os_air_loops.each do |os_air_loop|
209
+ oasys = os_air_loop.airLoopHVACOutdoorAirSystem
210
+ unless oasys.empty?
211
+ os_oasys = oasys.get
212
+ oactrl = os_oasys.getControllerOutdoorAir
213
+ oactrl.resetMinimumFractionofOutdoorAirSchedule
214
+ oactrl.setMinimumOutdoorAirSchedule(oa_sch)
215
+ end
196
216
  end
197
217
  end
198
218
  end
@@ -234,7 +254,7 @@ module Honeybee
234
254
  end
235
255
 
236
256
  # assign an electric humidifier if there's an air loop and the zones have a humidistat
237
- if os_air_loop
257
+ if !os_air_loops.empty?
238
258
  humidistat_exists = false
239
259
  zones.each do |zone|
240
260
  h_stat = zone.zoneControlHumidistat
@@ -243,7 +263,9 @@ module Honeybee
243
263
  end
244
264
  end
245
265
  if humidistat_exists
246
- humidifier = create_humidifier(openstudio_model, os_air_loop)
266
+ os_air_loops.each do |os_air_loop|
267
+ humidifier = create_humidifier(openstudio_model, os_air_loop)
268
+ end
247
269
  end
248
270
  end
249
271
 
@@ -253,7 +275,6 @@ module Honeybee
253
275
  sizing.setSizingOption('NonCoincident')
254
276
  end
255
277
 
256
- os_hvac
257
278
  end
258
279
 
259
280
  private
@@ -564,7 +564,7 @@ module Honeybee
564
564
  end
565
565
  elsif TemplateHVAC.types.include?(system_type)
566
566
  template_system = TemplateHVAC.new(hvac)
567
- os_template_system = template_system.to_openstudio(@openstudio_model, hvac['rooms'])
567
+ template_system.to_openstudio(@openstudio_model, hvac['rooms'])
568
568
  end
569
569
  end
570
570
  end
@@ -154,6 +154,7 @@ module Honeybee
154
154
  end
155
155
  end
156
156
  end
157
+
157
158
  # use the average of design day temperatures to set the water mains temperature
158
159
  os_water_mains = @openstudio_model.getSiteWaterMainsTemperature
159
160
  os_water_mains.setCalculationMethod('Correlation')
@@ -164,6 +165,62 @@ module Honeybee
164
165
  end
165
166
  os_water_mains.setMaximumDifferenceInMonthlyAverageOutdoorAirTemperatures(4)
166
167
 
168
+ # set the climate zone from design days assuming 0.4% extremes and normal distribution
169
+ climate_zone_objs = @openstudio_model.getClimateZones
170
+ ashrae_zones = climate_zone_objs.getClimateZones('ASHRAE')
171
+ if ashrae_zones.empty? && db_temps.length > 0
172
+ # generate temperatures according to a normal distribution
173
+ mean_temp = (db_temps.max + db_temps.min) / 2
174
+ dist_to_mean = db_temps.max - mean_temp
175
+ st_dev = dist_to_mean / 2.65
176
+ vals = []
177
+ for i in 0..4379
178
+ step_seed = i.to_f / 4380
179
+ add_val1, add_val2 = gaussian(mean_temp, st_dev, step_seed)
180
+ vals << add_val1
181
+ vals << add_val2
182
+ end
183
+
184
+ # compute the number of heating and cooling degree days
185
+ cooling_deg_days, heating_deg_days = 0, 0
186
+ vals.each do |temp|
187
+ if temp > 10
188
+ cdd = (temp - 10) / 24
189
+ cooling_deg_days += cdd
190
+ end
191
+ if temp < 18
192
+ hdd = (18 - temp) / 24
193
+ heating_deg_days += hdd
194
+ end
195
+ end
196
+
197
+ # determine the climate zone from the degree-day distribution
198
+ if cooling_deg_days > 5000
199
+ cz = '1'
200
+ elsif cooling_deg_days > 3500
201
+ cz = '2A'
202
+ elsif cooling_deg_days > 2500
203
+ cz = '3A'
204
+ elsif cooling_deg_days <= 2500 and heating_deg_days <= 2000
205
+ cz = '3C'
206
+ elsif cooling_deg_days <= 2500 and heating_deg_days <= 3000
207
+ cz = '4A'
208
+ elsif heating_deg_days <= 3000
209
+ cz = '4C'
210
+ elsif heating_deg_days <= 4000
211
+ cz = '5A'
212
+ elsif heating_deg_days <= 5000
213
+ cz = '6A'
214
+ elsif heating_deg_days <= 7000
215
+ cz = '7'
216
+ else
217
+ cz = '8'
218
+ end
219
+
220
+ # set the climate zone
221
+ climate_zone_objs.setClimateZone('ASHRAE', cz)
222
+ end
223
+
167
224
  # set Outputs for the simulation
168
225
  if @hash[:output]
169
226
  if @hash[:output][:outputs]
@@ -251,5 +308,15 @@ module Honeybee
251
308
 
252
309
  end
253
310
 
311
+ def gaussian(mean, stddev, seed)
312
+ # generate a gaussian distribution of values
313
+ theta = 2 * Math::PI * seed
314
+ rho = Math.sqrt(-2 * Math.log(1 - seed))
315
+ scale = stddev * rho
316
+ x = mean + scale * Math.cos(theta)
317
+ y = mean + scale * Math.sin(theta)
318
+ return x, y
319
+ end
320
+
254
321
  end #SimulationParameter
255
322
  end #Honeybee
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: honeybee-openstudio
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.30.5
4
+ version: 2.31.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tanushree Charan
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: exe
13
13
  cert_chain: []
14
- date: 2022-03-09 00:00:00.000000000 Z
14
+ date: 2022-03-14 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -302,6 +302,7 @@ files:
302
302
  - lib/to_openstudio/geometry/shade.rb
303
303
  - lib/to_openstudio/hvac/Model.hvac.rb
304
304
  - lib/to_openstudio/hvac/ideal_air.rb
305
+ - lib/to_openstudio/hvac/radiant.rb
305
306
  - lib/to_openstudio/hvac/template.rb
306
307
  - lib/to_openstudio/internalmass.rb
307
308
  - lib/to_openstudio/load/daylight.rb