openstudio-geb 0.3.1r → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (25) hide show
  1. checksums.yaml +4 -4
  2. data/lib/measures/GEB Metrics Report/resources/os_lib_reporting.rb +5 -24
  3. data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/LICENSE.md +13 -0
  4. data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/README.md +152 -0
  5. data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/README.md.erb +45 -0
  6. data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/docs/.gitkeep +0 -0
  7. data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/measure.rb +604 -0
  8. data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/measure.xml +265 -0
  9. data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/tests/USA_NY_Buffalo.Niagara.Intl.AP.725280_TMY3.epw +8768 -0
  10. data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/tests/add_fan_assist_night_ventilation_with_hybrid_control_test.rb +94 -0
  11. data/lib/measures/add_fan_assist_night_ventilation_with_hybrid_control/tests/medium_office_with_internal_windows.osm +13459 -0
  12. data/lib/measures/add_heat_pump_water_heater/measure.rb +2 -2
  13. data/lib/measures/apply_dynamic_coating_to_roof_wall/LICENSE.md +1 -0
  14. data/lib/measures/apply_dynamic_coating_to_roof_wall/README.md +101 -0
  15. data/lib/measures/apply_dynamic_coating_to_roof_wall/README.md.erb +45 -0
  16. data/lib/measures/apply_dynamic_coating_to_roof_wall/docs/.gitkeep +0 -0
  17. data/lib/measures/apply_dynamic_coating_to_roof_wall/measure.rb +421 -0
  18. data/lib/measures/apply_dynamic_coating_to_roof_wall/measure.xml +204 -0
  19. data/lib/measures/apply_dynamic_coating_to_roof_wall/tests/MediumOffice-90.1-2010-ASHRAE 169-2013-5A.osm +13669 -0
  20. data/lib/measures/apply_dynamic_coating_to_roof_wall/tests/SF-CACZ6-HPWH-pre1978.osm +16130 -0
  21. data/lib/measures/apply_dynamic_coating_to_roof_wall/tests/USA_NY_Buffalo.Niagara.Intl.AP.725280_TMY3.epw +8768 -0
  22. data/lib/measures/apply_dynamic_coating_to_roof_wall/tests/apply_dynamic_coating_to_roof_wall_test.rb +81 -0
  23. data/lib/openstudio/geb/run.rb +34 -0
  24. data/lib/openstudio/geb/version.rb +1 -1
  25. metadata +25 -5
@@ -14,11 +14,11 @@
14
14
 
15
15
  # start the measure
16
16
  class AddHpwh < OpenStudio::Measure::ModelMeasure
17
- # require 'openstudio-standards'
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 %>
@@ -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