openstudio-standards 0.1.13 → 0.1.14

Sign up to get free protection for your applications and to get access to all the features.
@@ -306,3 +306,178 @@ def adjust_infiltration_to_prototype_building_conditions(initial_infiltration_ra
306
306
 
307
307
  return adjusted_infiltration_rate_m3_per_s
308
308
  end
309
+
310
+ # Convert biquadratic curves that are a function of temperature
311
+ # from IP (F) to SI (C) or vice-versa. The curve is of the form
312
+ # z = C1 + C2*x + C3*x^2 + C4*y + C5*y^2 + C6*x*y
313
+ # where C1, C2, ... are the coefficients,
314
+ # x is the first independent variable (in F or C)
315
+ # y is the second independent variable (in F or C)
316
+ # and z is the resulting value
317
+ #
318
+ # @author Scott Horowitz, NREL
319
+ # @param coeffs [Array<Double>] an array of 6 coefficients, in order
320
+ # @return [Array<Double>] the revised coefficients in the new unit system
321
+ def convert_curve_biquadratic(coeffs, ip_to_si=true)
322
+ if ip_to_si
323
+ # Convert IP curves to SI curves
324
+ si_coeffs = []
325
+ si_coeffs << coeffs[0] + 32.0 * (coeffs[1] + coeffs[3]) + 1024.0 * (coeffs[2] + coeffs[4] + coeffs[5])
326
+ si_coeffs << 9.0 / 5.0 * coeffs[1] + 576.0 / 5.0 * coeffs[2] + 288.0 / 5.0 * coeffs[5]
327
+ si_coeffs << 81.0 / 25.0 * coeffs[2]
328
+ si_coeffs << 9.0 / 5.0 * coeffs[3] + 576.0 / 5.0 * coeffs[4] + 288.0 / 5.0 * coeffs[5]
329
+ si_coeffs << 81.0 / 25.0 * coeffs[4]
330
+ si_coeffs << 81.0 / 25.0 * coeffs[5]
331
+ return si_coeffs
332
+ else
333
+ # Convert SI curves to IP curves
334
+ ip_coeffs = []
335
+ ip_coeffs << coeffs[0] - 160.0/9.0 * (coeffs[1] + coeffs[3]) + 25600.0/81.0 * (coeffs[2] + coeffs[4] + coeffs[5])
336
+ ip_coeffs << 5.0/9.0 * (coeffs[1] - 320.0/9.0 * coeffs[2] - 160.0/9.0 * coeffs[5])
337
+ ip_coeffs << 25.0/81.0 * coeffs[2]
338
+ ip_coeffs << 5.0/9.0 * (coeffs[3] - 320.0/9.0 * coeffs[4] - 160.0/9.0 * coeffs[5])
339
+ ip_coeffs << 25.0/81.0 * coeffs[4]
340
+ ip_coeffs << 25.0/81.0 * coeffs[5]
341
+ return ip_coeffs
342
+ end
343
+ end
344
+
345
+ # Create a biquadratic curve of the form
346
+ # z = C1 + C2*x + C3*x^2 + C4*y + C5*y^2 + C6*x*y
347
+ #
348
+ # @author Scott Horowitz, NREL
349
+ # @param coeffs [Array<Double>] an array of 6 coefficients, in order
350
+ # @param crv_name [String] the name of the curve
351
+ # @param minX [Double] the minimum value of independent variable X that will be used
352
+ # @param maxX [Double] the maximum value of independent variable X that will be used
353
+ # @param minY [Double] the minimum value of independent variable Y that will be used
354
+ # @param maxY [Double] the maximum value of independent variable Y that will be used
355
+ # @param minOut [Double] the minimum value of dependent variable Z
356
+ # @param maxOut [Double] the maximum value of dependent variable Z
357
+ def create_curve_biquadratic(coeffs, crv_name, minX, maxX, minY, maxY, minOut, maxOut)
358
+ curve = OpenStudio::Model::CurveBiquadratic.new(self)
359
+ curve.setName(crv_name)
360
+ curve.setCoefficient1Constant(coeffs[0])
361
+ curve.setCoefficient2x(coeffs[1])
362
+ curve.setCoefficient3xPOW2(coeffs[2])
363
+ curve.setCoefficient4y(coeffs[3])
364
+ curve.setCoefficient5yPOW2(coeffs[4])
365
+ curve.setCoefficient6xTIMESY(coeffs[5])
366
+ curve.setMinimumValueofx(minX) unless minX.nil?
367
+ curve.setMaximumValueofx(maxX) unless maxX.nil?
368
+ curve.setMinimumValueofy(minY) unless minY.nil?
369
+ curve.setMaximumValueofy(maxY) unless maxY.nil?
370
+ curve.setMinimumCurveOutput(minOut) unless minOut.nil?
371
+ curve.setMaximumCurveOutput(maxOut) unless maxOut.nil?
372
+ return curve
373
+ end
374
+
375
+ # Create a bicubic curve of the form
376
+ # z = C1 + C2*x + C3*x^2 + C4*y + C5*y^2 + C6*x*y + C7*x^3 + C8*y^3 + C9*x^2*y + C10*x*y^2
377
+ #
378
+ # @author Scott Horowitz, NREL
379
+ # @param coeffs [Array<Double>] an array of 10 coefficients, in order
380
+ # @param crv_name [String] the name of the curve
381
+ # @param minX [Double] the minimum value of independent variable X that will be used
382
+ # @param maxX [Double] the maximum value of independent variable X that will be used
383
+ # @param minY [Double] the minimum value of independent variable Y that will be used
384
+ # @param maxY [Double] the maximum value of independent variable Y that will be used
385
+ # @param minOut [Double] the minimum value of dependent variable Z
386
+ # @param maxOut [Double] the maximum value of dependent variable Z
387
+ def create_curve_bicubic(coeffs, crv_name, minX, maxX, minY, maxY, minOut, maxOut)
388
+ curve = OpenStudio::Model::CurveBicubic.new(self)
389
+ curve.setName(crv_name)
390
+ curve.setCoefficient1Constant(coeffs[0])
391
+ curve.setCoefficient2x(coeffs[1])
392
+ curve.setCoefficient3xPOW2(coeffs[2])
393
+ curve.setCoefficient4y(coeffs[3])
394
+ curve.setCoefficient5yPOW2(coeffs[4])
395
+ curve.setCoefficient6xTIMESY(coeffs[5])
396
+ curve.setCoefficient7xPOW3(coeffs[6])
397
+ curve.setCoefficient8yPOW3(coeffs[7])
398
+ curve.setCoefficient9xPOW2TIMESY(coeffs[8])
399
+ curve.setCoefficient10xTIMESYPOW2(coeffs[9])
400
+ curve.setMinimumValueofx(minX) unless minX.nil?
401
+ curve.setMaximumValueofx(maxX) unless maxX.nil?
402
+ curve.setMinimumValueofy(minY) unless minY.nil?
403
+ curve.setMaximumValueofy(maxY) unless maxY.nil?
404
+ curve.setMinimumCurveOutput(minOut) unless minOut.nil?
405
+ curve.setMaximumCurveOutput(maxOut) unless maxOut.nil?
406
+ return curve
407
+ end
408
+
409
+ # Create a quadratic curve of the form
410
+ # z = C1 + C2*x + C3*x^2
411
+ #
412
+ # @author Scott Horowitz, NREL
413
+ # @param coeffs [Array<Double>] an array of 3 coefficients, in order
414
+ # @param crv_name [String] the name of the curve
415
+ # @param minX [Double] the minimum value of independent variable X that will be used
416
+ # @param maxX [Double] the maximum value of independent variable X that will be used
417
+ # @param minOut [Double] the minimum value of dependent variable Z
418
+ # @param maxOut [Double] the maximum value of dependent variable Z
419
+ # @param is_dimensionless [Bool] if true, the X independent variable is considered unitless
420
+ # and the resulting output dependent variable is considered unitless
421
+ def create_curve_quadratic(coeffs, crv_name, minX, maxX, minOut, maxOut, is_dimensionless=false)
422
+ curve = OpenStudio::Model::CurveQuadratic.new(self)
423
+ curve.setName(crv_name)
424
+ curve.setCoefficient1Constant(coeffs[0])
425
+ curve.setCoefficient2x(coeffs[1])
426
+ curve.setCoefficient3xPOW2(coeffs[2])
427
+ curve.setMinimumValueofx(minX) unless minX.nil?
428
+ curve.setMaximumValueofx(maxX) unless maxX.nil?
429
+ curve.setMinimumCurveOutput(minOut) unless minOut.nil?
430
+ curve.setMaximumCurveOutput(maxOut) unless maxOut.nil?
431
+ if is_dimensionless
432
+ curve.setInputUnitTypeforX("Dimensionless")
433
+ curve.setOutputUnitType("Dimensionless")
434
+ end
435
+ return curve
436
+ end
437
+
438
+ # Create a cubic curve of the form
439
+ # z = C1 + C2*x + C3*x^2 + C4*x^3
440
+ #
441
+ # @author Scott Horowitz, NREL
442
+ # @param coeffs [Array<Double>] an array of 4 coefficients, in order
443
+ # @param crv_name [String] the name of the curve
444
+ # @param minX [Double] the minimum value of independent variable X that will be used
445
+ # @param maxX [Double] the maximum value of independent variable X that will be used
446
+ # @param minOut [Double] the minimum value of dependent variable Z
447
+ # @param maxOut [Double] the maximum value of dependent variable Z
448
+ def create_curve_cubic(coeffs, crv_name, minX, maxX, minOut, maxOut)
449
+ curve = OpenStudio::Model::CurveCubic.new(self)
450
+ curve.setName(crv_name)
451
+ curve.setCoefficient1Constant(coeffs[0])
452
+ curve.setCoefficient2x(coeffs[1])
453
+ curve.setCoefficient3xPOW2(coeffs[2])
454
+ curve.setCoefficient4xPOW3(coeffs[3])
455
+ curve.setMinimumValueofx(minX) unless minX.nil?
456
+ curve.setMaximumValueofx(maxX) unless maxX.nil?
457
+ curve.setMinimumCurveOutput(minOut) unless minOut.nil?
458
+ curve.setMaximumCurveOutput(maxOut) unless maxOut.nil?
459
+ return curve
460
+ end
461
+
462
+ # Create an exponential curve of the form
463
+ # z = C1 + C2*x^C3
464
+ #
465
+ # @author Scott Horowitz, NREL
466
+ # @param coeffs [Array<Double>] an array of 3 coefficients, in order
467
+ # @param crv_name [String] the name of the curve
468
+ # @param minX [Double] the minimum value of independent variable X that will be used
469
+ # @param maxX [Double] the maximum value of independent variable X that will be used
470
+ # @param minOut [Double] the minimum value of dependent variable Z
471
+ # @param maxOut [Double] the maximum value of dependent variable Z
472
+ def create_curve_exponent(coeffs, crv_name, minX, maxX, minOut, maxOut)
473
+ curve = OpenStudio::Model::CurveExponent.new(self)
474
+ curve.setName(crv_name)
475
+ curve.setCoefficient1Constant(coeffs[0])
476
+ curve.setCoefficient2Constant(coeffs[1])
477
+ curve.setCoefficient3Constant(coeffs[2])
478
+ curve.setMinimumValueofx(minX) unless minX.nil?
479
+ curve.setMaximumValueofx(maxX) unless maxX.nil?
480
+ curve.setMinimumCurveOutput(minOut) unless minOut.nil?
481
+ curve.setMaximumCurveOutput(maxOut) unless maxOut.nil?
482
+ return curve
483
+ end
@@ -1244,9 +1244,9 @@ class OpenStudio::Model::Model
1244
1244
  end
1245
1245
 
1246
1246
  # If electric zone heat
1247
- electric_reheat = false
1247
+ reheat_type = 'Water'
1248
1248
  if zone_heat_fuel == 'Electricity'
1249
- electric_reheat = true
1249
+ reheat_type = 'Electricity'
1250
1250
  end
1251
1251
 
1252
1252
  # Group zones by story
@@ -1288,7 +1288,7 @@ class OpenStudio::Model::Model
1288
1288
  0.9,
1289
1289
  OpenStudio.convert(4.0, 'inH_{2}O', 'Pa').get,
1290
1290
  nil,
1291
- electric_reheat,
1291
+ reheat_type,
1292
1292
  nil)
1293
1293
  end
1294
1294
 
@@ -254,7 +254,7 @@ class OpenStudio::Model::PlantLoop
254
254
  # Determine the leaving CW temp
255
255
  max_leaving_cw_t_f = 85
256
256
  leaving_cw_t_10f_approach_f = design_oat_wb_f + 10
257
- leaving_cw_t_f = [max_leaving_cw_t_f, leaving_cw_t_10f_approach_f].max
257
+ leaving_cw_t_f = [max_leaving_cw_t_f, leaving_cw_t_10f_approach_f].min
258
258
 
259
259
  # Calculate the approach
260
260
  approach_r = leaving_cw_t_f - design_oat_wb_f
@@ -42,7 +42,7 @@ class OpenStudio::Model::ThermalZone
42
42
  oa_for_people = number_of_people * dsn_oa.outdoorAirFlowperPerson
43
43
  oa_for_floor_area = floor_area * dsn_oa.outdoorAirFlowperFloorArea
44
44
  oa_rate = dsn_oa.outdoorAirFlowRate
45
- oa_for_volume = volume * dsn_oa.outdoorAirFlowAirChangesperHour
45
+ oa_for_volume = volume * dsn_oa.outdoorAirFlowAirChangesperHour / 3600
46
46
 
47
47
  # First check if this space uses the Maximum method and other spaces do not
48
48
  if dsn_oa.outdoorAirMethod == 'Maximum'
@@ -1453,6 +1453,10 @@ class OpenStudio::Model::ThermalZone
1453
1453
  else
1454
1454
  sch_name = space_type_properties['exhaust_schedule']
1455
1455
  exhaust_schedule = model.add_schedule(sch_name)
1456
+ unless exhaust_schedule
1457
+ OpenStudio.logFree(OpenStudio::Warn, 'openstudio.Standards.ThermalZone', "Could not find an exhaust schedule called #{sch_name}, exhaust fans will run continuously.")
1458
+ exhaust_schedule = model.alwaysOnDiscreteSchedule
1459
+ end
1456
1460
  end
1457
1461
 
1458
1462
  # add exhaust fans
@@ -0,0 +1,174 @@
1
+ # Adds sql queries to the model
2
+ class OpenStudio::Model::Model
3
+
4
+ def sql_file
5
+
6
+ # Ensure that the model has a sql file associated with it
7
+ if self.sqlFile.empty?
8
+ OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', 'Failed to retrieve data because the sql file containing results is missing.')
9
+ return false
10
+ end
11
+
12
+ return self.sqlFile.get
13
+ end
14
+
15
+ def annual_occupied_unmet_hours
16
+
17
+ sql = self.sql_file
18
+
19
+ # setup the queries
20
+ heating_setpoint_unmet_query = "SELECT Value
21
+ FROM TabularDataWithStrings
22
+ WHERE ReportName='SystemSummary'
23
+ AND ReportForString='Entire Facility'
24
+ AND TableName='Time Setpoint Not Met'
25
+ AND RowName = 'Facility'
26
+ AND ColumnName='During Occupied Heating'"
27
+
28
+ cooling_setpoint_unmet_query = "SELECT Value
29
+ FROM TabularDataWithStrings
30
+ WHERE ReportName='SystemSummary'
31
+ AND ReportForString='Entire Facility'
32
+ AND TableName='Time Setpoint Not Met'
33
+ AND RowName = 'Facility'
34
+ AND ColumnName='During Occupied Cooling'"
35
+
36
+ # get the info
37
+ heating_setpoint_unmet = sql.execAndReturnFirstDouble(heating_setpoint_unmet_query)
38
+ cooling_setpoint_unmet = sql.execAndReturnFirstDouble(cooling_setpoint_unmet_query)
39
+
40
+ # make sure all the data are availalbe
41
+ if heating_setpoint_unmet.empty? || cooling_setpoint_unmet.empty?
42
+ OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', 'Could not get unmet hours information.')
43
+ return false
44
+ end
45
+
46
+ #aggregate heating and cooling hrs
47
+ heating_or_cooling_setpoint_unmet = heating_setpoint_unmet.get + cooling_setpoint_unmet.get
48
+
49
+ return heating_or_cooling_setpoint_unmet
50
+ end
51
+
52
+ def annual_occupied_unmet_heating_hours
53
+
54
+ sql = self.sql_file
55
+
56
+ # setup the queries
57
+ heating_setpoint_unmet_query = "SELECT Value
58
+ FROM TabularDataWithStrings
59
+ WHERE ReportName='SystemSummary'
60
+ AND ReportForString='Entire Facility'
61
+ AND TableName='Time Setpoint Not Met'
62
+ AND RowName = 'Facility'
63
+ AND ColumnName='During Occupied Heating'"
64
+
65
+ # get the info
66
+ heating_setpoint_unmet = sql.execAndReturnFirstDouble(heating_setpoint_unmet_query)
67
+
68
+ # make sure all the data are availalbe
69
+ if heating_setpoint_unmet.empty?
70
+ OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', 'Could not get unmet heating hours information.')
71
+ return false
72
+ end
73
+
74
+ return heating_setpoint_unmet.get
75
+ end
76
+
77
+ def annual_occupied_unmet_cooling_hours
78
+
79
+ sql = self.sql_file
80
+
81
+ # setup the queries
82
+ cooling_setpoint_unmet_query = "SELECT Value
83
+ FROM TabularDataWithStrings
84
+ WHERE ReportName='SystemSummary'
85
+ AND ReportForString='Entire Facility'
86
+ AND TableName='Time Setpoint Not Met'
87
+ AND RowName = 'Facility'
88
+ AND ColumnName='During Occupied Cooling'"
89
+
90
+ # get the info
91
+ cooling_setpoint_unmet = sql.execAndReturnFirstDouble(cooling_setpoint_unmet_query)
92
+
93
+ # make sure all the data are availalbe
94
+ if cooling_setpoint_unmet.empty?
95
+ OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', 'Could not get unmet cooling hours information.')
96
+ return false
97
+ end
98
+
99
+ return cooling_setpoint_unmet.get
100
+ end
101
+
102
+ def annual_eui_kbtu_per_ft2
103
+
104
+ sql = self.sql_file
105
+
106
+ building = self.getBuilding
107
+
108
+ # make sure all required data are available
109
+ if sql.totalSiteEnergy.empty?
110
+ OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', 'Site energy data unavailable.')
111
+ return false
112
+ end
113
+
114
+ total_site_energy_kBtu = OpenStudio::convert(sql.totalSiteEnergy.get, "GJ", "kBtu").get
115
+
116
+ floor_area_ft2 = OpenStudio::convert(building.floorArea, "m^2", "ft^2").get
117
+
118
+ site_eui_kbtu_per_ft2 = total_site_energy_kBtu / floor_area_ft2
119
+
120
+ return site_eui_kbtu_per_ft2
121
+ end
122
+
123
+ def net_conditioned_floor_area
124
+
125
+ sql = self.sql_file
126
+
127
+ # setup the queries
128
+ area_query = "SELECT Value
129
+ FROM TabularDataWithStrings
130
+ WHERE ReportName='AnnualBuildingUtilityPerformanceSummary'
131
+ AND ReportForString='Entire Facility'
132
+ AND TableName='Building Area'
133
+ AND RowName = 'Net Conditioned Building Area'
134
+ AND ColumnName='Area'"
135
+
136
+ # get the info
137
+ area_m2 = sql.execAndReturnFirstDouble(area_query)
138
+
139
+ # make sure all the data are availalbe
140
+ if area_m2.empty?
141
+ OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', 'Could not get conditioned area information.')
142
+ return false
143
+ end
144
+
145
+ return area_m2.get
146
+ end
147
+
148
+ def annual_energy_by_fuel_and_enduse(fuel_type, end_use)
149
+
150
+ sql = self.sql_file
151
+
152
+ # setup the queries
153
+ query = "SELECT Value
154
+ FROM TabularDataWithStrings
155
+ WHERE ReportName='AnnualBuildingUtilityPerformanceSummary'
156
+ AND ReportForString='Entire Facility'
157
+ AND TableName='End Uses'
158
+ AND RowName = '#{end_use}'
159
+ AND ColumnName='#{fuel_type}'"
160
+
161
+ # get the info
162
+ energy_gj = sql.execAndReturnFirstDouble(query)
163
+
164
+ # make sure all the data are availalbe
165
+ if energy_gj.empty?
166
+ OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', "Could not get energy for #{fuel_type} #{end_use}.")
167
+ return 0.0
168
+ end
169
+
170
+ return energy_gj.get
171
+
172
+ end
173
+
174
+ end
@@ -1,3 +1,3 @@
1
1
  module OpenstudioStandards
2
- VERSION = '0.1.13'.freeze
2
+ VERSION = '0.1.14'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openstudio-standards
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.13
4
+ version: 0.1.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Parker
@@ -21,7 +21,7 @@ authors:
21
21
  autorequire:
22
22
  bindir: bin
23
23
  cert_chain: []
24
- date: 2017-03-24 00:00:00.000000000 Z
24
+ date: 2017-06-15 00:00:00.000000000 Z
25
25
  dependencies:
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: nokogiri
@@ -733,6 +733,7 @@ files:
733
733
  - lib/openstudio-standards/utilities/hash.rb
734
734
  - lib/openstudio-standards/utilities/logging.rb
735
735
  - lib/openstudio-standards/utilities/simulation.rb
736
+ - lib/openstudio-standards/utilities/sqlfile.rb
736
737
  - lib/openstudio-standards/version.rb
737
738
  - lib/openstudio-standards/weather/Weather.Model.rb
738
739
  - lib/openstudio-standards/weather/Weather.stat_file.rb