openstudio-geb 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/measures/GEB Metrics Report/resources/os_lib_reporting.rb +5 -24
- data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/LICENSE.md +13 -0
- data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/README.md +152 -0
- data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/README.md.erb +45 -0
- data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/docs/.gitkeep +0 -0
- data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/measure.rb +604 -0
- data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/measure.xml +265 -0
- data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/tests/USA_NY_Buffalo.Niagara.Intl.AP.725280_TMY3.epw +8768 -0
- data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/tests/add_fan_assist_night_ventilation_with_hybrid_control_test.rb +94 -0
- data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/tests/medium_office_with_internal_windows.osm +13459 -0
- data/lib/measures/add_heat_pump_water_heater/measure.rb +2 -2
- data/lib/measures/apply_dynamic_coating_to_roof_wall/LICENSE.md +1 -0
- data/lib/measures/apply_dynamic_coating_to_roof_wall/README.md +101 -0
- data/lib/measures/apply_dynamic_coating_to_roof_wall/README.md.erb +45 -0
- data/lib/measures/apply_dynamic_coating_to_roof_wall/docs/.gitkeep +0 -0
- data/lib/measures/apply_dynamic_coating_to_roof_wall/measure.rb +421 -0
- data/lib/measures/apply_dynamic_coating_to_roof_wall/measure.xml +204 -0
- data/lib/measures/apply_dynamic_coating_to_roof_wall/tests/MediumOffice-90.1-2010-ASHRAE 169-2013-5A.osm +13669 -0
- data/lib/measures/apply_dynamic_coating_to_roof_wall/tests/SF-CACZ6-HPWH-pre1978.osm +16130 -0
- data/lib/measures/apply_dynamic_coating_to_roof_wall/tests/USA_NY_Buffalo.Niagara.Intl.AP.725280_TMY3.epw +8768 -0
- data/lib/measures/apply_dynamic_coating_to_roof_wall/tests/apply_dynamic_coating_to_roof_wall_test.rb +81 -0
- data/lib/openstudio/geb/run.rb +34 -0
- data/lib/openstudio/geb/version.rb +1 -1
- metadata +23 -3
@@ -14,11 +14,11 @@
|
|
14
14
|
|
15
15
|
# start the measure
|
16
16
|
class AddHpwh < OpenStudio::Measure::ModelMeasure
|
17
|
-
|
17
|
+
require 'openstudio-standards'
|
18
18
|
|
19
19
|
# (03/02/2022 note) Public release of openstudio-standards gem has bug in model_add_heatpump_water_heater and model_add_water_heater
|
20
20
|
# so temporarily require this local customized version. The bug has been fixed in developing branch so should be publicly available soon
|
21
|
-
require '/Users/sky/.rvm/gems/ruby-2.7.2/gems/openstudio-standards-0.2.15/lib/openstudio-standards'
|
21
|
+
# require '/Users/sky/.rvm/gems/ruby-2.7.2/gems/openstudio-standards-0.2.15/lib/openstudio-standards'
|
22
22
|
|
23
23
|
# human readable name
|
24
24
|
def name
|
@@ -0,0 +1 @@
|
|
1
|
+
Insert your license here
|
@@ -0,0 +1,101 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
###### (Automatically generated documentation)
|
4
|
+
|
5
|
+
# Apply dynamic coating to roof wall
|
6
|
+
|
7
|
+
## Description
|
8
|
+
This measure applies dynamic coating on the outside of opaque exterior walls and/or roofs. The thermal and/or solar absorptance of the outer layer material will vary with the selected control signal. This measure is meant to reduce the radiative and solar heat gain via roofs and/or walls.
|
9
|
+
|
10
|
+
## Modeler Description
|
11
|
+
This measure modifies the thermal and/or solar absorptance of the outer surface of an existing material so that they can vary with the selected control signal. The related object is available in EnergyPlus version 23.1, but not yet implemented in OpenStudio, so this measure is implemented as an EnergyPlus measure.
|
12
|
+
|
13
|
+
## Measure Type
|
14
|
+
EnergyPlusMeasure
|
15
|
+
|
16
|
+
## Taxonomy
|
17
|
+
|
18
|
+
|
19
|
+
## Arguments
|
20
|
+
|
21
|
+
|
22
|
+
### Select where to apply the dynamic coating:
|
23
|
+
|
24
|
+
**Name:** apply_where,
|
25
|
+
**Type:** Choice,
|
26
|
+
**Units:** ,
|
27
|
+
**Required:** true,
|
28
|
+
**Model Dependent:** false
|
29
|
+
|
30
|
+
**Choice Display Names** ["Roof Only", "Wall Only", "Both"]
|
31
|
+
|
32
|
+
|
33
|
+
### Select the type of properties that the dynamic coating modifies:
|
34
|
+
|
35
|
+
**Name:** apply_type,
|
36
|
+
**Type:** Choice,
|
37
|
+
**Units:** ,
|
38
|
+
**Required:** true,
|
39
|
+
**Model Dependent:** false
|
40
|
+
|
41
|
+
**Choice Display Names** ["Thermal Only", "Solar Only", "Both"]
|
42
|
+
|
43
|
+
|
44
|
+
### We use two specific points to describe the linear relationship between surface temperature and absorptance, this is the surface temperature of the left point in Degree Celcius.
|
45
|
+
|
46
|
+
**Name:** temp_lo,
|
47
|
+
**Type:** Double,
|
48
|
+
**Units:** ,
|
49
|
+
**Required:** true,
|
50
|
+
**Model Dependent:** false
|
51
|
+
|
52
|
+
|
53
|
+
### We use two specific points to describe the linear relationship between surface temperature and absorptance, this is the surface temperature of the right point in Degree Celcius.
|
54
|
+
|
55
|
+
**Name:** temp_hi,
|
56
|
+
**Type:** Double,
|
57
|
+
**Units:** ,
|
58
|
+
**Required:** true,
|
59
|
+
**Model Dependent:** false
|
60
|
+
|
61
|
+
|
62
|
+
### Thermal absorptance at low temperature point.
|
63
|
+
|
64
|
+
**Name:** therm_abs_at_temp_lo,
|
65
|
+
**Type:** Double,
|
66
|
+
**Units:** ,
|
67
|
+
**Required:** false,
|
68
|
+
**Model Dependent:** false
|
69
|
+
|
70
|
+
|
71
|
+
### Thermal absorptance at high temperature point.
|
72
|
+
|
73
|
+
**Name:** therm_abs_at_temp_hi,
|
74
|
+
**Type:** Double,
|
75
|
+
**Units:** ,
|
76
|
+
**Required:** false,
|
77
|
+
**Model Dependent:** false
|
78
|
+
|
79
|
+
|
80
|
+
### Solar absorptance at low temperature point.
|
81
|
+
|
82
|
+
**Name:** solar_abs_at_temp_lo,
|
83
|
+
**Type:** Double,
|
84
|
+
**Units:** ,
|
85
|
+
**Required:** false,
|
86
|
+
**Model Dependent:** false
|
87
|
+
|
88
|
+
|
89
|
+
### Solar absorptance at high temperature point.
|
90
|
+
|
91
|
+
**Name:** solar_abs_at_temp_hi,
|
92
|
+
**Type:** Double,
|
93
|
+
**Units:** ,
|
94
|
+
**Required:** false,
|
95
|
+
**Model Dependent:** false
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
<%#= README.md.erb is used to auto-generate README.md. %>
|
2
|
+
<%#= To manually maintain README.md throw away README.md.erb and manually edit README.md %>
|
3
|
+
###### (Automatically generated documentation)
|
4
|
+
|
5
|
+
# <%= name %>
|
6
|
+
|
7
|
+
## Description
|
8
|
+
<%= description %>
|
9
|
+
|
10
|
+
## Modeler Description
|
11
|
+
<%= modelerDescription %>
|
12
|
+
|
13
|
+
## Measure Type
|
14
|
+
<%= measureType %>
|
15
|
+
|
16
|
+
## Taxonomy
|
17
|
+
<%= taxonomy %>
|
18
|
+
|
19
|
+
## Arguments
|
20
|
+
|
21
|
+
<% arguments.each do |argument| %>
|
22
|
+
### <%= argument[:display_name] %>
|
23
|
+
<%= argument[:description] %>
|
24
|
+
**Name:** <%= argument[:name] %>,
|
25
|
+
**Type:** <%= argument[:type] %>,
|
26
|
+
**Units:** <%= argument[:units] %>,
|
27
|
+
**Required:** <%= argument[:required] %>,
|
28
|
+
**Model Dependent:** <%= argument[:model_dependent] %>
|
29
|
+
<% if argument[:type] == "Choice" && !argument[:model_dependent]%>
|
30
|
+
**Choice Display Names** <%= argument[:choice_display_names] %>
|
31
|
+
<% end %>
|
32
|
+
<% end %>
|
33
|
+
|
34
|
+
<% if arguments.size == 0 %>
|
35
|
+
<%= "This measure does not have any user arguments" %>
|
36
|
+
<% end %>
|
37
|
+
|
38
|
+
<% if outputs.size > 0 %>
|
39
|
+
## Outputs
|
40
|
+
<% output_names = [] %>
|
41
|
+
<% outputs.each do |output| %>
|
42
|
+
<% output_names << output[:display_name] %>
|
43
|
+
<% end %>
|
44
|
+
<%= output_names.join(", ") %>
|
45
|
+
<% end %>
|
File without changes
|
@@ -0,0 +1,421 @@
|
|
1
|
+
# insert your copyright here
|
2
|
+
|
3
|
+
# see the URL below for information on how to write OpenStudio measures
|
4
|
+
# http://nrel.github.io/OpenStudio-user-documentation/reference/measure_writing_guide/
|
5
|
+
|
6
|
+
# start the measure
|
7
|
+
class ApplyDynamicCoatingToRoofWall < OpenStudio::Measure::EnergyPlusMeasure
|
8
|
+
# human readable name
|
9
|
+
def name
|
10
|
+
# Measure name should be the title case of the class name.
|
11
|
+
return 'Apply dynamic coating to roof wall'
|
12
|
+
end
|
13
|
+
|
14
|
+
# human readable description
|
15
|
+
def description
|
16
|
+
return 'This measure applies dynamic coating on the outside of opaque exterior walls and/or roofs. The thermal ' \
|
17
|
+
'and/or solar absorptance of the outer layer material will vary with the selected control signal. ' \
|
18
|
+
'This measure is meant to reduce the radiative and solar heat gain via roofs and/or walls.'
|
19
|
+
end
|
20
|
+
|
21
|
+
# human readable description of modeling approach
|
22
|
+
def modeler_description
|
23
|
+
return 'This measure modifies the thermal and/or solar absorptance of the outer surface of an existing material so that ' \
|
24
|
+
'they can vary with the selected control signal. The related object is available in EnergyPlus version 23.1, ' \
|
25
|
+
'but not yet implemented in OpenStudio, so this measure is implemented as an EnergyPlus measure.'
|
26
|
+
end
|
27
|
+
|
28
|
+
# define the arguments that the user will input
|
29
|
+
def arguments(workspace)
|
30
|
+
args = OpenStudio::Measure::OSArgumentVector.new
|
31
|
+
|
32
|
+
# Make choice argument for roof and wall application
|
33
|
+
apply_where = OpenStudio::Measure::OSArgument::makeChoiceArgument('apply_where', ['Roof Only', 'Wall Only', 'Both'], true)
|
34
|
+
apply_where.setDisplayName('Select where to apply the dynamic coating:')
|
35
|
+
apply_where.setDefaultValue('Roof Only')
|
36
|
+
args << apply_where
|
37
|
+
|
38
|
+
# Make choice argument for modification types
|
39
|
+
apply_type = OpenStudio::Measure::OSArgument::makeChoiceArgument('apply_type', ['Thermal Only', 'Solar Only', 'Both'], true)
|
40
|
+
apply_type.setDisplayName('Select the type of properties that the dynamic coating modifies:')
|
41
|
+
apply_type.setDefaultValue('Both')
|
42
|
+
args << apply_type
|
43
|
+
|
44
|
+
# assuming linear relationship between control signal (SurfaceTemperature) and thermal/solar absorptance
|
45
|
+
# the thermal absorptance (i.e., emittance for opaque) increases from 0.2 at 19°C to 0.9 at 27°C
|
46
|
+
# ref: K Tang et al., Temperature-adaptive radiative coating for all-season household thermal regulation.
|
47
|
+
# (http://nano.eecs.berkeley.edu/publications/Science_2021_TARC.pdf) page SM-7 (supplemental material)
|
48
|
+
# For solar absorptance, the temperature range is the same 19-27C, solar absorptance varies from 0.9 to 0.1
|
49
|
+
# ref: K. Dong et al., 2022. Reducing temperature swing of space objects with temperature-adaptive solar or radiative coating. Cell Reports Physical Science.
|
50
|
+
# (https://www.sciencedirect.com/science/article/pii/S2666386422003605) page 3
|
51
|
+
|
52
|
+
# We use two specific points to describe the linear relationship between surface temperature and absorptance
|
53
|
+
# This is the surface temperature of the left point
|
54
|
+
temp_lo = OpenStudio::Measure::OSArgument.makeDoubleArgument('temp_lo', true)
|
55
|
+
temp_lo.setDisplayName('We use two specific points to describe the linear relationship between surface temperature and absorptance, this is the surface temperature of the left point in Degree Celcius.')
|
56
|
+
temp_lo.setDefaultValue(19)
|
57
|
+
args << temp_lo
|
58
|
+
|
59
|
+
# We use two specific points to describe the linear relationship between surface temperature and absorptance
|
60
|
+
# This is the surface temperature of the right point
|
61
|
+
temp_hi = OpenStudio::Measure::OSArgument.makeDoubleArgument('temp_hi', true)
|
62
|
+
temp_hi.setDisplayName('We use two specific points to describe the linear relationship between surface temperature and absorptance, this is the surface temperature of the right point in Degree Celcius.')
|
63
|
+
temp_hi.setDefaultValue(27)
|
64
|
+
args << temp_hi
|
65
|
+
|
66
|
+
# thermal absorptance at low temperature point
|
67
|
+
therm_abs_at_temp_lo = OpenStudio::Measure::OSArgument.makeDoubleArgument('therm_abs_at_temp_lo', false)
|
68
|
+
therm_abs_at_temp_lo.setDisplayName('Thermal absorptance at low temperature point.')
|
69
|
+
therm_abs_at_temp_lo.setDefaultValue(0.2)
|
70
|
+
args << therm_abs_at_temp_lo
|
71
|
+
|
72
|
+
# thermal absorptance at high temperature point
|
73
|
+
therm_abs_at_temp_hi = OpenStudio::Measure::OSArgument.makeDoubleArgument('therm_abs_at_temp_hi', false)
|
74
|
+
therm_abs_at_temp_hi.setDisplayName('Thermal absorptance at high temperature point.')
|
75
|
+
therm_abs_at_temp_hi.setDefaultValue(0.9)
|
76
|
+
args << therm_abs_at_temp_hi
|
77
|
+
|
78
|
+
# solar absorptance at low temperature point
|
79
|
+
solar_abs_at_temp_lo = OpenStudio::Measure::OSArgument.makeDoubleArgument('solar_abs_at_temp_lo', false)
|
80
|
+
solar_abs_at_temp_lo.setDisplayName('Solar absorptance at low temperature point.')
|
81
|
+
solar_abs_at_temp_lo.setDefaultValue(0.9)
|
82
|
+
args << solar_abs_at_temp_lo
|
83
|
+
|
84
|
+
# solar absorptance at high temperature point
|
85
|
+
solar_abs_at_temp_hi = OpenStudio::Measure::OSArgument.makeDoubleArgument('solar_abs_at_temp_hi', false)
|
86
|
+
solar_abs_at_temp_hi.setDisplayName('Solar absorptance at high temperature point.')
|
87
|
+
solar_abs_at_temp_hi.setDefaultValue(0.1)
|
88
|
+
args << solar_abs_at_temp_hi
|
89
|
+
|
90
|
+
|
91
|
+
return args
|
92
|
+
end
|
93
|
+
|
94
|
+
# define what happens when the measure is run
|
95
|
+
def run(workspace, runner, user_arguments)
|
96
|
+
super(workspace, runner, user_arguments)
|
97
|
+
|
98
|
+
# use the built-in error checking
|
99
|
+
if !runner.validateUserArguments(arguments(workspace), user_arguments)
|
100
|
+
return false
|
101
|
+
end
|
102
|
+
|
103
|
+
# assign the user inputs to variables
|
104
|
+
apply_where = runner.getStringArgumentValue('apply_where', user_arguments)
|
105
|
+
apply_type = runner.getStringArgumentValue('apply_type', user_arguments)
|
106
|
+
temp_lo = runner.getDoubleArgumentValue('temp_lo', user_arguments)
|
107
|
+
temp_hi = runner.getDoubleArgumentValue('temp_hi', user_arguments)
|
108
|
+
therm_abs_at_temp_lo = runner.getOptionalDoubleArgumentValue('therm_abs_at_temp_lo', user_arguments)
|
109
|
+
therm_abs_at_temp_hi = runner.getOptionalDoubleArgumentValue('therm_abs_at_temp_hi', user_arguments)
|
110
|
+
solar_abs_at_temp_lo = runner.getOptionalDoubleArgumentValue('solar_abs_at_temp_lo', user_arguments)
|
111
|
+
solar_abs_at_temp_hi = runner.getOptionalDoubleArgumentValue('solar_abs_at_temp_hi', user_arguments)
|
112
|
+
|
113
|
+
# temp_hi should be higher than temp_lo
|
114
|
+
if temp_hi <= temp_lo
|
115
|
+
runner.registerError("temp_hi should be higher than temp_lo, current: temp_hi #{temp_hi} temp_lo #{temp_lo}. User can use default value 27C and 19C.")
|
116
|
+
return false
|
117
|
+
end
|
118
|
+
|
119
|
+
# check temp_hi and temp_lo for rationality
|
120
|
+
if temp_hi > 100
|
121
|
+
runner.registerError("Current temp_hi #{temp_hi}C is higher than 100C, which is abnormal. Default value is 27C")
|
122
|
+
return false
|
123
|
+
elsif temp_hi < -50
|
124
|
+
runner.registerError("Current temp_hi #{temp_hi}C is lower than -50C, which is abnormal. Default value is 27C")
|
125
|
+
return false
|
126
|
+
end
|
127
|
+
if temp_lo > 100
|
128
|
+
runner.registerError("Current temp_lo #{temp_lo}C is higher than 100C, which is abnormal. Default value is 19C")
|
129
|
+
return false
|
130
|
+
elsif temp_lo < -50
|
131
|
+
runner.registerError("Current temp_lo #{temp_lo}C is lower than -50C, which is abnormal. Default value is 19C")
|
132
|
+
return false
|
133
|
+
end
|
134
|
+
|
135
|
+
def check_input(input_var, input_name, default, min, max)
|
136
|
+
# check for rationality
|
137
|
+
if input_var.empty?
|
138
|
+
runner.registerError("#{input_name} needs input, can use default value #{default}.")
|
139
|
+
return false
|
140
|
+
elsif input_var.to_f <= min || input_var.to_f >= max
|
141
|
+
runner.registerError("Invalid #{input_name} of #{input_var.to_f} entered. Value must be >#{min} and <#{max}.")
|
142
|
+
return false
|
143
|
+
else
|
144
|
+
return true
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# based on changed property type, check inputs for rationality
|
149
|
+
case apply_type
|
150
|
+
when 'Both'
|
151
|
+
check_input(therm_abs_at_temp_lo, 'therm_abs_at_temp_lo', 0.2, 0, 1)
|
152
|
+
check_input(therm_abs_at_temp_hi, 'therm_abs_at_temp_hi', 0.9, 0, 1)
|
153
|
+
check_input(solar_abs_at_temp_lo, 'solar_abs_at_temp_lo', 0.9, 0, 1)
|
154
|
+
check_input(solar_abs_at_temp_hi, 'solar_abs_at_temp_hi', 0.2, 0, 1)
|
155
|
+
when 'Thermal Only'
|
156
|
+
check_input(therm_abs_at_temp_lo, 'therm_abs_at_temp_lo', 0.2, 0, 1)
|
157
|
+
check_input(therm_abs_at_temp_hi, 'therm_abs_at_temp_hi', 0.9, 0, 1)
|
158
|
+
when 'Solar Only'
|
159
|
+
check_input(solar_abs_at_temp_lo, 'solar_abs_at_temp_lo', 0.9, 0, 1)
|
160
|
+
check_input(solar_abs_at_temp_hi, 'solar_abs_at_temp_hi', 0.2, 0, 1)
|
161
|
+
else
|
162
|
+
runner.registerError("Invalid applied changed property type #{apply_type}, should be 'Thermal Only', 'Solar Only', or 'Both'")
|
163
|
+
return false
|
164
|
+
end
|
165
|
+
|
166
|
+
# loop through "BuildingSurface" to find all constructions for exterior walls and roofs, extract the unique materials used in outer layer
|
167
|
+
all_surfaces = workspace.getObjectsByType('BuildingSurface:Detailed'.to_IddObjectType)
|
168
|
+
ext_walls = []
|
169
|
+
ext_roofs = []
|
170
|
+
ext_wall_const_names = [] # unique set of exterior wall construction names
|
171
|
+
ext_roof_const_names = [] # unique set of exterior roof construction names
|
172
|
+
ext_wall_outer_layer_mats = [] # unique set of wall outer layer materials
|
173
|
+
ext_roof_outer_layer_mats = [] # unique set of roof outer layer materials
|
174
|
+
|
175
|
+
# find all exterior walls and roofs
|
176
|
+
all_surfaces.each do |surface|
|
177
|
+
next if surface.getString(5).to_s.downcase != 'outdoors'
|
178
|
+
if surface.getString(1).to_s.downcase == 'wall' # String(1) is "Surface Type"; String(5) is "Outside Boundary Condition"
|
179
|
+
ext_walls.push(surface)
|
180
|
+
elsif surface.getString(1).to_s.downcase == 'roof'
|
181
|
+
ext_roofs.push(surface)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# extract the unique material set used in exterior walls and roofs' outer layer
|
186
|
+
ext_walls.each do |wall_surf|
|
187
|
+
const_name = wall_surf.getString(2).to_s # String(2) is "Construction Name"
|
188
|
+
next if ext_wall_const_names.include?const_name
|
189
|
+
ext_wall_const_names.push const_name
|
190
|
+
const_obj = workspace.getObjectsByName(const_name)[0] # get the construction object
|
191
|
+
outer_layer_name = const_obj.getString(1).get # String(1) is the outside layer
|
192
|
+
outer_layer_name1 = const_obj.getField(1).get # String(1) is the outside layer
|
193
|
+
puts "const_obj:#{const_obj}"
|
194
|
+
puts "const_name:#{const_name}"
|
195
|
+
puts "outer_layer_name:#{outer_layer_name}; #{outer_layer_name1}"
|
196
|
+
outer_layer_mat_obj = workspace.getObjectsByName(outer_layer_name)[0] # get the outside layer material object
|
197
|
+
puts "outer_layer_mat_obj: #{outer_layer_mat_obj}"
|
198
|
+
puts "outer_layer_mat_obj.name = #{outer_layer_mat_obj.name}"
|
199
|
+
ext_wall_outer_layer_mats.push outer_layer_mat_obj unless ext_wall_outer_layer_mats.include?outer_layer_mat_obj
|
200
|
+
end
|
201
|
+
ext_roofs.each do |roof_surf|
|
202
|
+
const_name = roof_surf.getString(2).to_s # String(2) is "Construction Name"
|
203
|
+
next if ext_roof_const_names.include?const_name
|
204
|
+
ext_roof_const_names.push const_name
|
205
|
+
const_obj = workspace.getObjectsByName(const_name)[0] # get the construction object
|
206
|
+
outer_layer_name = const_obj.getString(1).to_s # String(1) is the outside layer
|
207
|
+
puts "const_name:#{const_name}"
|
208
|
+
puts "outer_layer_name:#{outer_layer_name}"
|
209
|
+
outer_layer_mat_obj = workspace.getObjectsByName(outer_layer_name)[0] # get the outside layer material object
|
210
|
+
ext_roof_outer_layer_mats.push outer_layer_mat_obj unless ext_roof_outer_layer_mats.include?outer_layer_mat_obj
|
211
|
+
end
|
212
|
+
|
213
|
+
# initial condition: get the original thermal and solar absorptance of the roof and wall outer layer material
|
214
|
+
ini_wall_therm_abs_list = []
|
215
|
+
ini_wall_solar_abs_list = []
|
216
|
+
ini_roof_therm_abs_list = []
|
217
|
+
ini_roof_solar_abs_list = []
|
218
|
+
ext_wall_outer_layer_mats.each do |mat|
|
219
|
+
# get the material object type
|
220
|
+
mat_type = mat.idfObject().iddObject().name.to_s
|
221
|
+
if mat_type == "Material"
|
222
|
+
ini_wall_therm_abs_list << mat.getString(6).get.to_f if mat.getString(6).get.to_f > 0
|
223
|
+
ini_wall_solar_abs_list << mat.getString(7).get.to_f if mat.getString(7).get.to_f > 0
|
224
|
+
elsif mat_type == "Material:NoMass"
|
225
|
+
ini_wall_therm_abs_list << mat.getString(3).get.to_f if mat.getString(3).get.to_f > 0
|
226
|
+
ini_wall_solar_abs_list << mat.getString(4).get.to_f if mat.getString(4).get.to_f > 0
|
227
|
+
end
|
228
|
+
end
|
229
|
+
ext_roof_outer_layer_mats.each do |mat|
|
230
|
+
# get the material object type
|
231
|
+
mat_type = mat.idfObject().iddObject().name.to_s
|
232
|
+
if mat_type == "Material"
|
233
|
+
ini_roof_therm_abs_list << mat.getString(6).get.to_f if mat.getString(6).get.to_f > 0
|
234
|
+
ini_roof_solar_abs_list << mat.getString(7).get.to_f if mat.getString(7).get.to_f > 0
|
235
|
+
elsif mat_type == "Material:NoMass"
|
236
|
+
ini_roof_therm_abs_list << mat.getString(3).get.to_f if mat.getString(3).get.to_f > 0
|
237
|
+
ini_roof_solar_abs_list << mat.getString(4).get.to_f if mat.getString(4).get.to_f > 0
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
runner.registerInitialCondition("The initial exterior wall thermal absorptance is #{ini_wall_therm_abs_list}, exterior wall solar absorptance is #{ini_wall_solar_abs_list}, "\
|
242
|
+
"exterior roof thermal absorptance is #{ini_roof_therm_abs_list}, exterior roof solar absorptance is #{ini_roof_solar_abs_list}. ")
|
243
|
+
|
244
|
+
# By default control signal is "SurfaceTemperature" as the other modes haven't been tested thoroughly in E+
|
245
|
+
# loop through "BuildingSurface" to find all constructions for exterior walls and roofs, extract the unique materials used in outer layer
|
246
|
+
# add variableabsorptance properties to these materials
|
247
|
+
# pre-populate the object strings for thermal and solar variableabsorptance related objects
|
248
|
+
thermal_abs_objs_strs = ["
|
249
|
+
Table:IndependentVariable,
|
250
|
+
ThermalAbsorptanceTemperatureTable_IndependentVariable1, !- Name
|
251
|
+
Linear, !- Interpolation Method
|
252
|
+
Constant, !- Extrapolation Method
|
253
|
+
-40.0, !- Minimum Value
|
254
|
+
60.0, !- Maximum Value
|
255
|
+
, !- Normalization Reference Value
|
256
|
+
Temperature, !- Unit Type
|
257
|
+
, !- External File Name
|
258
|
+
, !- External File Column Number
|
259
|
+
, !- External File Starting Row Number
|
260
|
+
0.0, !- Value 1
|
261
|
+
#{temp_lo}, !- Value 2
|
262
|
+
#{temp_hi}, !- <none>
|
263
|
+
40.00000; !- <none>
|
264
|
+
",
|
265
|
+
"
|
266
|
+
Table:IndependentVariableList,
|
267
|
+
ThermalAbsorptanceTemperatureTable_IndependentVariableList, !- Name
|
268
|
+
ThermalAbsorptanceTemperatureTable_IndependentVariable1; !- Independent Variable 1 Name
|
269
|
+
",
|
270
|
+
"
|
271
|
+
Table:Lookup,
|
272
|
+
ThermalAbsorptanceTemperatureTable, !- Name
|
273
|
+
ThermalAbsorptanceTemperatureTable_IndependentVariableList, !- Independent Variable List Name
|
274
|
+
, !- Normalization Method
|
275
|
+
, !- Normalization Divisor
|
276
|
+
#{therm_abs_at_temp_lo}, !- Minimum Output
|
277
|
+
#{therm_abs_at_temp_hi}, !- Maximum Output
|
278
|
+
Dimensionless, !- Output Unit Type
|
279
|
+
, !- External File Name
|
280
|
+
, !- External File Column Number
|
281
|
+
, !- External File Starting Row Number
|
282
|
+
#{therm_abs_at_temp_lo}, !- Output Value 1
|
283
|
+
#{therm_abs_at_temp_lo}, !- Output Value 2
|
284
|
+
#{therm_abs_at_temp_hi}, !- <none>
|
285
|
+
#{therm_abs_at_temp_hi}; !- <none>
|
286
|
+
"
|
287
|
+
]
|
288
|
+
|
289
|
+
solar_abs_objs_strs = ["
|
290
|
+
Table:IndependentVariable,
|
291
|
+
SolarAbsorptanceTemperatureTable_IndependentVariable1, !- Name
|
292
|
+
Linear, !- Interpolation Method
|
293
|
+
Constant, !- Extrapolation Method
|
294
|
+
-40.0, !- Minimum Value
|
295
|
+
60.0, !- Maximum Value
|
296
|
+
, !- Normalization Reference Value
|
297
|
+
Temperature, !- Unit Type
|
298
|
+
, !- External File Name
|
299
|
+
, !- External File Column Number
|
300
|
+
, !- External File Starting Row Number
|
301
|
+
0.0, !- Value 1
|
302
|
+
#{temp_lo}, !- Value 2
|
303
|
+
#{temp_hi}, !- <none>
|
304
|
+
40.00000; !- <none>
|
305
|
+
",
|
306
|
+
"
|
307
|
+
Table:IndependentVariableList,
|
308
|
+
SolarAbsorptanceTemperatureTable_IndependentVariableList, !- Name
|
309
|
+
SolarAbsorptanceTemperatureTable_IndependentVariable1; !- Independent Variable 1 Name
|
310
|
+
",
|
311
|
+
"
|
312
|
+
Table:Lookup,
|
313
|
+
SolarAbsorptanceTemperatureTable, !- Name
|
314
|
+
SolarAbsorptanceTemperatureTable_IndependentVariableList, !- Independent Variable List Name
|
315
|
+
, !- Normalization Method
|
316
|
+
, !- Normalization Divisor
|
317
|
+
#{solar_abs_at_temp_hi}, !- Minimum Output
|
318
|
+
#{solar_abs_at_temp_lo}, !- Maximum Output
|
319
|
+
Dimensionless, !- Output Unit Type
|
320
|
+
, !- External File Name
|
321
|
+
, !- External File Column Number
|
322
|
+
, !- External File Starting Row Number
|
323
|
+
#{solar_abs_at_temp_lo}, !- Output Value 1
|
324
|
+
#{solar_abs_at_temp_lo}, !- Output Value 2
|
325
|
+
#{solar_abs_at_temp_hi}, !- <none>
|
326
|
+
#{solar_abs_at_temp_hi}; !- <none>
|
327
|
+
"
|
328
|
+
]
|
329
|
+
|
330
|
+
def add_dynamic_coating_mat_str(mat_list, apply_type, workspace)
|
331
|
+
# array to hold new IDF objects needed for dynamic coating materials
|
332
|
+
string_objects = []
|
333
|
+
|
334
|
+
mat_list.each do |mat|
|
335
|
+
puts "mat: #{mat}"
|
336
|
+
mat_name = mat.getString(0).to_s # name
|
337
|
+
# no need to clone the material object (in case it is also used in other constructions) because thermal and solar absorptances only matter when the material is on the outside layer
|
338
|
+
puts "mat_name: #{mat_name}"
|
339
|
+
|
340
|
+
# based on applied surfaces type, add material objects
|
341
|
+
case apply_type
|
342
|
+
when 'Both'
|
343
|
+
matprops_obj_str = "
|
344
|
+
MaterialProperty:VariableAbsorptance,
|
345
|
+
variable_#{mat_name}, !- Name
|
346
|
+
#{mat_name}, !- Reference Material Name
|
347
|
+
SurfaceTemperature, !- Control Signal
|
348
|
+
ThermalAbsorptanceTemperatureTable, !- Trigger Solar Absorptance Function Name
|
349
|
+
, !- Thermal Absorptance Schedule Name
|
350
|
+
SolarAbsorptanceTemperatureTable, !- Trigger Solar Absorptance Function Name
|
351
|
+
; !- Solar Absorptance Schedule Name
|
352
|
+
"
|
353
|
+
string_objects << matprops_obj_str
|
354
|
+
when 'Thermal Only'
|
355
|
+
matprops_obj_str = "
|
356
|
+
MaterialProperty:VariableAbsorptance,
|
357
|
+
variable_#{mat_name}, !- Name
|
358
|
+
#{mat_name}, !- Reference Material Name
|
359
|
+
SurfaceTemperature, !- Control Signal
|
360
|
+
ThermalAbsorptanceTemperatureTable, !- Trigger Solar Absorptance Function Name
|
361
|
+
, !- Thermal Absorptance Schedule Name
|
362
|
+
, !- Trigger Solar Absorptance Function Name
|
363
|
+
; !- Solar Absorptance Schedule Name
|
364
|
+
"
|
365
|
+
string_objects << matprops_obj_str
|
366
|
+
when 'Solar Only'
|
367
|
+
matprops_obj_str = "
|
368
|
+
MaterialProperty:VariableAbsorptance,
|
369
|
+
variable_#{mat_name}, !- Name
|
370
|
+
#{mat_name}, !- Reference Material Name
|
371
|
+
SurfaceTemperature, !- Control Signal
|
372
|
+
, !- Trigger Solar Absorptance Function Name
|
373
|
+
, !- Thermal Absorptance Schedule Name
|
374
|
+
SolarAbsorptanceTemperatureTable, !- Trigger Solar Absorptance Function Name
|
375
|
+
; !- Solar Absorptance Schedule Name
|
376
|
+
"
|
377
|
+
string_objects << matprops_obj_str
|
378
|
+
else
|
379
|
+
runner.registerError("Invalid applied changed property type #{apply_type}, should be 'Thermal Only', 'Solar Only', or 'Both'")
|
380
|
+
return false
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
return string_objects
|
385
|
+
end
|
386
|
+
|
387
|
+
# loop through each targeted outer layer material and add variableabsorptance properties to these materials
|
388
|
+
altered_mats = [] # for final condition output
|
389
|
+
case apply_where
|
390
|
+
when 'Roof Only'
|
391
|
+
string_objects = add_dynamic_coating_mat_str(ext_roof_outer_layer_mats, apply_type, workspace)
|
392
|
+
altered_mats = ext_roof_outer_layer_mats
|
393
|
+
when 'Wall Only'
|
394
|
+
string_objects = add_dynamic_coating_mat_str(ext_wall_outer_layer_mats, apply_type, workspace)
|
395
|
+
altered_mats = ext_wall_outer_layer_mats
|
396
|
+
when 'Both'
|
397
|
+
string_objects = add_dynamic_coating_mat_str(ext_roof_outer_layer_mats+ext_wall_outer_layer_mats, apply_type, workspace)
|
398
|
+
altered_mats = ext_roof_outer_layer_mats+ext_wall_outer_layer_mats
|
399
|
+
else
|
400
|
+
runner.registerError("Invalid selection on where to apply the dynamic coating, current: #{apply_where}, should be 'Roof Only', 'Wall Only', or 'Both'.")
|
401
|
+
return false
|
402
|
+
end
|
403
|
+
# add the commonly used properties objects
|
404
|
+
string_objects = string_objects + thermal_abs_objs_strs + solar_abs_objs_strs
|
405
|
+
|
406
|
+
# add all of the strings to workspace
|
407
|
+
string_objects.each do |string_object|
|
408
|
+
idfObject = OpenStudio::IdfObject.load(string_object)
|
409
|
+
object = idfObject.get
|
410
|
+
workspace.addObject(object)
|
411
|
+
end
|
412
|
+
|
413
|
+
# report final condition of model
|
414
|
+
runner.registerFinalCondition("The dynamic coating is applied to the following materials: #{altered_mats.map{|mat| mat.getString(0).to_s}}. ")
|
415
|
+
|
416
|
+
return true
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
# register the measure to be used by the application
|
421
|
+
ApplyDynamicCoatingToRoofWall.new.registerWithApplication
|