urbanopt-cli 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/nightly_build.yml +60 -0
  3. data/CHANGELOG.md +12 -0
  4. data/CMakeLists.txt +8 -8
  5. data/FindOpenStudioSDK.cmake +10 -10
  6. data/LICENSE.md +1 -1
  7. data/README.md +25 -23
  8. data/Rakefile +1 -1
  9. data/example_files/Gemfile +2 -0
  10. data/example_files/mappers/Baseline.rb +155 -155
  11. data/example_files/mappers/ClassProject.rb +4 -4
  12. data/example_files/mappers/CreateBar.rb +1 -1
  13. data/example_files/mappers/EvCharging.rb +1 -1
  14. data/example_files/mappers/FlexibleHotWater.rb +1 -1
  15. data/example_files/mappers/Floorspace.rb +1 -1
  16. data/example_files/mappers/HighEfficiency.rb +1 -1
  17. data/example_files/mappers/HighEfficiencyCreateBar.rb +1 -1
  18. data/example_files/mappers/HighEfficiencyFloorspace.rb +1 -1
  19. data/example_files/mappers/PeakHoursMelsShedding.rb +1 -1
  20. data/example_files/mappers/PeakHoursThermostatAdjust.rb +1 -1
  21. data/example_files/mappers/ThermalStorage.rb +1 -1
  22. data/example_files/measures/BuildResidentialModel/measure.rb +3 -3
  23. data/example_files/measures/BuildResidentialModel/measure.xml +3 -3
  24. data/example_files/measures/BuildResidentialModel/resources/util.rb +45 -45
  25. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/measure.rb +7 -0
  26. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/measure.xml +18 -10
  27. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/resources/schedules.rb +15 -0
  28. data/example_files/resources/hpxml-measures/BuildResidentialScheduleFile/tests/build_residential_schedule_file_test.rb +53 -5
  29. data/example_files/resources/hpxml-measures/Changelog.md +39 -28
  30. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/measure.xml +27 -27
  31. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/battery.rb +9 -4
  32. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/hpxml_defaults.rb +5 -4
  33. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/version.rb +2 -2
  34. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/waterheater.rb +5 -1
  35. data/example_files/resources/hpxml-measures/HPXMLtoOpenStudio/tests/test_defaults.rb +28 -10
  36. data/example_files/resources/hpxml-measures/ReportSimulationOutput/measure.rb +6 -1
  37. data/example_files/resources/hpxml-measures/ReportSimulationOutput/measure.xml +3 -3
  38. data/example_files/resources/hpxml-measures/docs/source/usage_instructions.rst +2 -1
  39. data/example_files/resources/hpxml-measures/docs/source/workflow_inputs.rst +14 -10
  40. data/example_files/resources/hpxml-measures/docs/source/workflow_outputs.rst +4 -4
  41. data/example_files/resources/hpxml-measures/workflow/template-run-hpxml-with-stochastic-occupancy-subset.osw +64 -0
  42. data/example_files/resources/hpxml-measures/workflow/template-run-hpxml-with-stochastic-occupancy.osw +2 -2
  43. data/example_files/resources/hpxml-measures/workflow/tests/base_results/results.csv +12 -12
  44. data/example_files/resources/hpxml-measures/workflow/tests/hpxml_translator_test.rb +36 -110
  45. data/lib/uo_cli/version.rb +2 -2
  46. data/lib/uo_cli.rb +62 -67
  47. data/uo_cli.gemspec +3 -1
  48. metadata +32 -3
  49. data/requirements.txt +0 -2
@@ -80,17 +80,17 @@ class MathTools
80
80
  end
81
81
 
82
82
  def self.interp2(x, x0, x1, f0, f1)
83
- '''
83
+ '
84
84
  Returns the linear interpolation between two results.
85
- '''
85
+ '
86
86
 
87
87
  return f0 + ((x - x0) / (x1 - x0)) * (f1 - f0)
88
88
  end
89
89
 
90
90
  def self.interp4(x, y, x1, x2, y1, y2, fx1y1, fx1y2, fx2y1, fx2y2)
91
- '''
91
+ '
92
92
  Returns the bilinear interpolation between four results.
93
- '''
93
+ '
94
94
 
95
95
  return (fx1y1 / ((x2 - x1) * (y2 - y1))) * (x2 - x) * (y2 - y) \
96
96
  + (fx2y1 / ((x2 - x1) * (y2 - y1))) * (x - x1) * (y2 - y) \
@@ -99,7 +99,7 @@ class MathTools
99
99
  end
100
100
 
101
101
  def self.biquadratic(x, y, c)
102
- '''
102
+ '
103
103
  Description:
104
104
  ------------
105
105
  Calculate the result of a biquadratic polynomial with independent variables
@@ -113,7 +113,7 @@ class MathTools
113
113
  Outputs:
114
114
  --------
115
115
  z float result of biquadratic polynomial
116
- '''
116
+ '
117
117
  if c.length != 6
118
118
  puts 'Error: There must be 6 coefficients in a biquadratic polynomial'
119
119
  end
@@ -122,7 +122,7 @@ class MathTools
122
122
  end
123
123
 
124
124
  def self.quadratic(x, c)
125
- '''
125
+ '
126
126
  Description:
127
127
  ------------
128
128
  Calculate the result of a quadratic polynomial with independent variable
@@ -138,7 +138,7 @@ class MathTools
138
138
  Outputs:
139
139
  --------
140
140
  y float result of biquadratic polynomial
141
- '''
141
+ '
142
142
  if c.size != 3
143
143
  puts 'Error: There must be 3 coefficients in a quadratic polynomial'
144
144
  end
@@ -148,7 +148,7 @@ class MathTools
148
148
  end
149
149
 
150
150
  def self.bicubic(x, y, c)
151
- '''
151
+ '
152
152
  Description:
153
153
  ------------
154
154
  Calculate the result of a bicubic polynomial with independent variables
@@ -166,7 +166,7 @@ class MathTools
166
166
  Outputs:
167
167
  --------
168
168
  z float result of bicubic polynomial
169
- '''
169
+ '
170
170
  if c.size != 10
171
171
  puts 'Error: There must be 10 coefficients in a bicubic polynomial'
172
172
  end
@@ -177,7 +177,7 @@ class MathTools
177
177
  end
178
178
 
179
179
  def self.Iterate(x0, f0, x1, f1, x2, f2, icount, cvg)
180
- '''
180
+ '
181
181
  Description:
182
182
  ------------
183
183
  Determine if a guess is within tolerance for convergence
@@ -225,7 +225,7 @@ class MathTools
225
225
  else:
226
226
  print "x did NOT converge after", i, "iterations"
227
227
  print "x, when f(x) is", f,"is", x
228
- '''
228
+ '
229
229
 
230
230
  tolRel = 1e-5
231
231
  dx = 0.1
@@ -987,16 +987,16 @@ class OutputMeters
987
987
  plant_loop.supplyComponents.each do |supply_component|
988
988
  next unless supply_component.to_BoilerHotWater.is_initialized
989
989
 
990
- if units_served.length != 1 # this is a central system
991
- if supply_component.to_BoilerHotWater.get.fuelType == 'Electricity'
992
- custom_meter_infos['Central:ElectricityHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler Electric Energy']
993
- end
994
- custom_meter_infos['Central:ElectricityHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler Ancillary Electric Energy']
995
- else
990
+ if units_served.length == 1
996
991
  if supply_component.to_BoilerHotWater.get.fuelType == 'Electricity'
997
992
  custom_meter_infos["#{unit.name}:ElectricityHeating"]['key_var_groups'] << [supply_component.name.to_s, 'Boiler Electric Energy']
998
993
  end
999
994
  custom_meter_infos["#{unit.name}:ElectricityHeating"]['key_var_groups'] << [supply_component.name.to_s, 'Boiler Ancillary Electric Energy']
995
+ else # this is a central system
996
+ if supply_component.to_BoilerHotWater.get.fuelType == 'Electricity'
997
+ custom_meter_infos['Central:ElectricityHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler Electric Energy']
998
+ end
999
+ custom_meter_infos['Central:ElectricityHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler Ancillary Electric Energy']
1000
1000
  end
1001
1001
  end
1002
1002
  end
@@ -1029,16 +1029,16 @@ class OutputMeters
1029
1029
  plant_loop.supplyComponents.each do |supply_component|
1030
1030
  next unless supply_component.to_BoilerHotWater.is_initialized
1031
1031
 
1032
- if units_served.length != 1 # this is a central system
1033
- if supply_component.to_BoilerHotWater.get.fuelType == 'Electricity'
1034
- custom_meter_infos['Central:ElectricityHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler Electric Energy']
1035
- end
1036
- custom_meter_infos['Central:ElectricityHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler Ancillary Electric Energy']
1037
- else
1032
+ if units_served.length == 1
1038
1033
  if supply_component.to_BoilerHotWater.get.fuelType == 'Electricity'
1039
1034
  custom_meter_infos["#{unit.name}:ElectricityHeating"]['key_var_groups'] << [supply_component.name.to_s, 'Boiler Electric Energy']
1040
1035
  end
1041
1036
  custom_meter_infos["#{unit.name}:ElectricityHeating"]['key_var_groups'] << [supply_component.name.to_s, 'Boiler Ancillary Electric Energy']
1037
+ else # this is a central system
1038
+ if supply_component.to_BoilerHotWater.get.fuelType == 'Electricity'
1039
+ custom_meter_infos['Central:ElectricityHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler Electric Energy']
1040
+ end
1041
+ custom_meter_infos['Central:ElectricityHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler Ancillary Electric Energy']
1042
1042
  end
1043
1043
  end
1044
1044
  end
@@ -1089,10 +1089,10 @@ class OutputMeters
1089
1089
  plant_loop.supplyComponents.each do |supply_component|
1090
1090
  next unless supply_component.to_ChillerElectricEIR.is_initialized
1091
1091
 
1092
- if units_served.length != 1 # this is a central system
1093
- custom_meter_infos['Central:ElectricityCooling']['key_var_groups'] << [supply_component.name.to_s, 'Chiller Electric Energy']
1094
- else
1092
+ if units_served.length == 1
1095
1093
  custom_meter_infos["#{unit.name}:ElectricityCooling"]['key_var_groups'] << [supply_component.name.to_s, 'Chiller Electric Energy']
1094
+ else # this is a central system
1095
+ custom_meter_infos['Central:ElectricityCooling']['key_var_groups'] << [supply_component.name.to_s, 'Chiller Electric Energy']
1096
1096
  end
1097
1097
  end
1098
1098
  end
@@ -1317,10 +1317,10 @@ class OutputMeters
1317
1317
  next unless supply_component.to_BoilerHotWater.is_initialized
1318
1318
  next if supply_component.to_BoilerHotWater.get.fuelType != 'NaturalGas'
1319
1319
 
1320
- if units_served.length != 1 # this is a central system
1321
- custom_meter_infos['Central:NaturalGasHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler Gas Energy']
1322
- else
1320
+ if units_served.length == 1
1323
1321
  custom_meter_infos["#{unit.name}:NaturalGasHeating"]['key_var_groups'] << [supply_component.name.to_s, 'Boiler Gas Energy']
1322
+ else # this is a central system
1323
+ custom_meter_infos['Central:NaturalGasHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler Gas Energy']
1324
1324
  end
1325
1325
  end
1326
1326
  end
@@ -1350,10 +1350,10 @@ class OutputMeters
1350
1350
  next unless supply_component.to_BoilerHotWater.is_initialized
1351
1351
  next if supply_component.to_BoilerHotWater.get.fuelType != 'NaturalGas'
1352
1352
 
1353
- if units_served.length != 1 # this is a central system
1354
- custom_meter_infos['Central:NaturalGasHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler Gas Energy']
1355
- else
1353
+ if units_served.length == 1
1356
1354
  custom_meter_infos["#{unit.name}:NaturalGasHeating"]['key_var_groups'] << [supply_component.name.to_s, 'Boiler Gas Energy']
1355
+ else # this is a central system
1356
+ custom_meter_infos['Central:NaturalGasHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler Gas Energy']
1357
1357
  end
1358
1358
  end
1359
1359
  end
@@ -1446,10 +1446,10 @@ class OutputMeters
1446
1446
  next unless supply_component.to_BoilerHotWater.is_initialized
1447
1447
  next if supply_component.to_BoilerHotWater.get.fuelType != 'FuelOil#1'
1448
1448
 
1449
- if units_served.length != 1 # this is a central system
1450
- custom_meter_infos['Central:FuelOilHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler FuelOil#1 Energy']
1451
- else
1449
+ if units_served.length == 1
1452
1450
  custom_meter_infos["#{unit.name}:FuelOilHeating"]['key_var_groups'] << [supply_component.name.to_s, 'Boiler FuelOil#1 Energy']
1451
+ else # this is a central system
1452
+ custom_meter_infos['Central:FuelOilHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler FuelOil#1 Energy']
1453
1453
  end
1454
1454
  end
1455
1455
  end
@@ -1479,10 +1479,10 @@ class OutputMeters
1479
1479
  next unless supply_component.to_BoilerHotWater.is_initialized
1480
1480
  next if supply_component.to_BoilerHotWater.get.fuelType != 'FuelOil#1'
1481
1481
 
1482
- if units_served.length != 1 # this is a central system
1483
- custom_meter_infos['Central:FuelOilHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler FuelOil#1 Energy']
1484
- else
1482
+ if units_served.length == 1
1485
1483
  custom_meter_infos["#{unit.name}:FuelOilHeating"]['key_var_groups'] << [supply_component.name.to_s, 'Boiler FuelOil#1 Energy']
1484
+ else # this is a central system
1485
+ custom_meter_infos['Central:FuelOilHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler FuelOil#1 Energy']
1486
1486
  end
1487
1487
  end
1488
1488
  end
@@ -1549,10 +1549,10 @@ class OutputMeters
1549
1549
  next unless supply_component.to_BoilerHotWater.is_initialized
1550
1550
  next if supply_component.to_BoilerHotWater.get.fuelType != 'PropaneGas'
1551
1551
 
1552
- if units_served.length != 1 # this is a central system
1553
- custom_meter_infos['Central:PropaneHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler Propane Energy']
1554
- else
1552
+ if units_served.length == 1
1555
1553
  custom_meter_infos["#{unit.name}:PropaneHeating"]['key_var_groups'] << [supply_component.name.to_s, 'Boiler Propane Energy']
1554
+ else # this is a central system
1555
+ custom_meter_infos['Central:PropaneHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler Propane Energy']
1556
1556
  end
1557
1557
  end
1558
1558
  end
@@ -1582,10 +1582,10 @@ class OutputMeters
1582
1582
  next unless supply_component.to_BoilerHotWater.is_initialized
1583
1583
  next if supply_component.to_BoilerHotWater.get.fuelType != 'PropaneGas'
1584
1584
 
1585
- if units_served.length != 1 # this is a central system
1586
- custom_meter_infos['Central:PropaneHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler Propane Energy']
1587
- else
1585
+ if units_served.length == 1
1588
1586
  custom_meter_infos["#{unit.name}:PropaneHeating"]['key_var_groups'] << [supply_component.name.to_s, 'Boiler Propane Energy']
1587
+ else # this is a central system
1588
+ custom_meter_infos['Central:PropaneHeating']['key_var_groups'] << [supply_component.name.to_s, 'Boiler Propane Energy']
1589
1589
  end
1590
1590
  end
1591
1591
  end
@@ -51,6 +51,11 @@ class BuildResidentialScheduleFile < OpenStudio::Measure::ModelMeasure
51
51
  arg.setDefaultValue('smooth')
52
52
  args << arg
53
53
 
54
+ arg = OpenStudio::Measure::OSArgument.makeStringArgument('schedules_column_names', false)
55
+ arg.setDisplayName('Schedules: Column Names')
56
+ arg.setDescription("A comma-separated list of the column names to generate. If not provided, defaults to all columns. Possible column names are: #{SchedulesFile.OccupancyColumnNames.join(', ')}.")
57
+ args << arg
58
+
54
59
  arg = OpenStudio::Measure::OSArgument.makeStringArgument('schedules_vacancy_period', false)
55
60
  arg.setDisplayName('Schedules: Vacancy Period')
56
61
  arg.setDescription('Specifies the vacancy period. Enter a date like "Dec 15 - Jan 15".')
@@ -161,6 +166,7 @@ class BuildResidentialScheduleFile < OpenStudio::Measure::ModelMeasure
161
166
  info_msgs << "RandomSeed=#{args[:random_seed]}" if args[:schedules_random_seed].is_initialized
162
167
  info_msgs << "GeometryNumOccupants=#{args[:geometry_num_occupants]}"
163
168
  info_msgs << "VacancyPeriod=#{args[:schedules_vacancy_period].get}" if args[:schedules_vacancy_period].is_initialized
169
+ info_msgs << "ColumnNames=#{args[:column_names]}" if args[:schedules_column_names].is_initialized
164
170
 
165
171
  runner.registerInfo("Created #{args[:schedules_type]} schedule with #{info_msgs.join(', ')}")
166
172
 
@@ -188,6 +194,7 @@ class BuildResidentialScheduleFile < OpenStudio::Measure::ModelMeasure
188
194
  args[:state] = hpxml.header.state_code if !hpxml.header.state_code.nil?
189
195
 
190
196
  args[:random_seed] = args[:schedules_random_seed].get if args[:schedules_random_seed].is_initialized
197
+ args[:column_names] = args[:schedules_column_names].get.split(',').map(&:strip) if args[:schedules_column_names].is_initialized
191
198
 
192
199
  if hpxml.building_occupancy.number_of_residents.nil?
193
200
  args[:geometry_num_occupants] = Geometry.get_occupancy_default_num(hpxml.building_construction.number_of_bedrooms)
@@ -3,8 +3,8 @@
3
3
  <schema_version>3.0</schema_version>
4
4
  <name>build_residential_schedule_file</name>
5
5
  <uid>f770b2db-1a9f-4e99-99a7-7f3161a594b1</uid>
6
- <version_id>b9ab9559-30d8-4b1c-9757-8c911f80e937</version_id>
7
- <version_modified>20221031T233528Z</version_modified>
6
+ <version_id>3a88a262-1431-4bb9-a577-cd235aed6b1e</version_id>
7
+ <version_modified>20221201T013247Z</version_modified>
8
8
  <xml_checksum>03F02484</xml_checksum>
9
9
  <class_name>BuildResidentialScheduleFile</class_name>
10
10
  <display_name>Schedule File Builder</display_name>
@@ -38,6 +38,14 @@
38
38
  </choice>
39
39
  </choices>
40
40
  </argument>
41
+ <argument>
42
+ <name>schedules_column_names</name>
43
+ <display_name>Schedules: Column Names</display_name>
44
+ <description>A comma-separated list of the column names to generate. If not provided, defaults to all columns. Possible column names are: occupants, lighting_interior, lighting_exterior, lighting_garage, lighting_exterior_holiday, cooking_range, refrigerator, extra_refrigerator, freezer, dishwasher, clothes_washer, clothes_dryer, ceiling_fan, plug_loads_other, plug_loads_tv, plug_loads_vehicle, plug_loads_well_pump, fuel_loads_grill, fuel_loads_lighting, fuel_loads_fireplace, pool_pump, pool_heater, hot_tub_pump, hot_tub_heater, hot_water_dishwasher, hot_water_clothes_washer, hot_water_fixtures.</description>
45
+ <type>String</type>
46
+ <required>false</required>
47
+ <model_dependent>false</model_dependent>
48
+ </argument>
41
49
  <argument>
42
50
  <name>schedules_vacancy_period</name>
43
51
  <display_name>Schedules: Vacancy Period</display_name>
@@ -890,11 +898,17 @@
890
898
  <usage_type>resource</usage_type>
891
899
  <checksum>127D96AC</checksum>
892
900
  </file>
901
+ <file>
902
+ <filename>schedules.rb</filename>
903
+ <filetype>rb</filetype>
904
+ <usage_type>resource</usage_type>
905
+ <checksum>AC348B70</checksum>
906
+ </file>
893
907
  <file>
894
908
  <filename>build_residential_schedule_file_test.rb</filename>
895
909
  <filetype>rb</filetype>
896
910
  <usage_type>test</usage_type>
897
- <checksum>41CA164F</checksum>
911
+ <checksum>10DD8842</checksum>
898
912
  </file>
899
913
  <file>
900
914
  <version>
@@ -905,13 +919,7 @@
905
919
  <filename>measure.rb</filename>
906
920
  <filetype>rb</filetype>
907
921
  <usage_type>script</usage_type>
908
- <checksum>8FF07C66</checksum>
909
- </file>
910
- <file>
911
- <filename>schedules.rb</filename>
912
- <filetype>rb</filetype>
913
- <usage_type>resource</usage_type>
914
- <checksum>F2E6EBB8</checksum>
922
+ <checksum>3D8ADC7F</checksum>
915
923
  </file>
916
924
  </files>
917
925
  </measure>
@@ -8,6 +8,7 @@ class ScheduleGenerator
8
8
  def initialize(runner:,
9
9
  epw_file:,
10
10
  state:,
11
+ column_names: nil,
11
12
  random_seed: nil,
12
13
  minutes_per_step:,
13
14
  steps_in_day:,
@@ -21,6 +22,7 @@ class ScheduleGenerator
21
22
  @runner = runner
22
23
  @epw_file = epw_file
23
24
  @state = state
25
+ @column_names = column_names
24
26
  @random_seed = random_seed
25
27
  @minutes_per_step = minutes_per_step
26
28
  @steps_in_day = steps_in_day
@@ -60,6 +62,16 @@ class ScheduleGenerator
60
62
  def create(args:)
61
63
  initialize_schedules
62
64
 
65
+ if @column_names.nil?
66
+ @column_names = SchedulesFile.ColumnNames
67
+ end
68
+
69
+ invalid_columns = (@column_names - SchedulesFile.ColumnNames)
70
+ invalid_columns.each do |invalid_column|
71
+ @runner.registerError("Invalid column name specified: '#{invalid_column}'.")
72
+ end
73
+ return false unless invalid_columns.empty?
74
+
63
75
  success = create_average_schedules
64
76
  return false if not success
65
77
 
@@ -963,6 +975,9 @@ class ScheduleGenerator
963
975
  end
964
976
 
965
977
  def export(schedules_path:)
978
+ (SchedulesFile.ColumnNames - @column_names).each do |col_to_remove|
979
+ @schedules.delete(col_to_remove)
980
+ end
966
981
  CSV.open(schedules_path, 'w') do |csv|
967
982
  csv << @schedules.keys
968
983
  rows = @schedules.values.transpose
@@ -180,6 +180,51 @@ class BuildResidentialScheduleFileTest < Minitest::Test
180
180
  assert(!sf.schedules.keys.include?(SchedulesFile::ColumnVacancy))
181
181
  end
182
182
 
183
+ def test_stochastic_subset_of_columns
184
+ hpxml = _create_hpxml('base.xml')
185
+ XMLHelper.write_file(hpxml.to_oga, @tmp_hpxml_path)
186
+
187
+ columns = [SchedulesFile::ColumnCookingRange,
188
+ SchedulesFile::ColumnDishwasher,
189
+ SchedulesFile::ColumnHotWaterDishwasher,
190
+ SchedulesFile::ColumnClothesWasher,
191
+ SchedulesFile::ColumnHotWaterClothesWasher,
192
+ SchedulesFile::ColumnClothesDryer,
193
+ SchedulesFile::ColumnHotWaterFixtures]
194
+
195
+ @args_hash['schedules_type'] = 'stochastic'
196
+ @args_hash['output_csv_path'] = File.absolute_path(File.join(@tmp_output_path, 'occupancy-stochastic.csv'))
197
+ @args_hash['schedules_column_names'] = columns.join(', ')
198
+ model, hpxml, result = _test_measure()
199
+
200
+ info_msgs = result.info.map { |x| x.logMessage }
201
+ assert(info_msgs.any? { |info_msg| info_msg.include?('ColumnNames') })
202
+
203
+ sf = SchedulesFile.new(model: model, schedules_paths: hpxml.header.schedules_filepaths)
204
+ sf.validate_schedules(year: 2007)
205
+
206
+ columns.each do |column|
207
+ assert(sf.schedules.keys.include?(column))
208
+ end
209
+ (SchedulesFile.ColumnNames - columns).each do |column|
210
+ assert(!sf.schedules.keys.include?(column))
211
+ end
212
+ end
213
+
214
+ def test_stochastic_subset_of_columns_invalid_name
215
+ hpxml = _create_hpxml('base.xml')
216
+ XMLHelper.write_file(hpxml.to_oga, @tmp_hpxml_path)
217
+
218
+ @args_hash['schedules_type'] = 'stochastic'
219
+ @args_hash['output_csv_path'] = File.absolute_path(File.join(@tmp_output_path, 'occupancy-stochastic.csv'))
220
+ @args_hash['schedules_column_names'] = "foobar, #{SchedulesFile::ColumnCookingRange}, foobar2"
221
+ _model, _hpxml, result = _test_measure(expect_fail: true)
222
+
223
+ error_msgs = result.errors.map { |x| x.logMessage }
224
+ assert(error_msgs.any? { |error_msg| error_msg.include?("Invalid column name specified: 'foobar'.") })
225
+ assert(error_msgs.any? { |error_msg| error_msg.include?("Invalid column name specified: 'foobar2'.") })
226
+ end
227
+
183
228
  def test_stochastic_vacancy
184
229
  hpxml = _create_hpxml('base.xml')
185
230
  XMLHelper.write_file(hpxml.to_oga, @tmp_hpxml_path)
@@ -508,7 +553,7 @@ class BuildResidentialScheduleFileTest < Minitest::Test
508
553
  end
509
554
  end
510
555
 
511
- def _test_measure()
556
+ def _test_measure(expect_fail: false)
512
557
  # create an instance of the measure
513
558
  measure = BuildResidentialScheduleFile.new
514
559
 
@@ -532,11 +577,14 @@ class BuildResidentialScheduleFileTest < Minitest::Test
532
577
  measure.run(model, runner, argument_map)
533
578
  result = runner.result
534
579
 
535
- # show the output
536
- show_output(result) unless result.value.valueName == 'Success'
537
-
538
580
  # assert that it ran correctly
539
- assert_equal('Success', result.value.valueName)
581
+ if expect_fail
582
+ show_output(result) unless result.value.valueName == 'Fail'
583
+ assert_equal('Fail', result.value.valueName)
584
+ else
585
+ show_output(result) unless result.value.valueName == 'Success'
586
+ assert_equal('Success', result.value.valueName)
587
+ end
540
588
 
541
589
  hpxml = HPXML.new(hpxml_path: @tmp_hpxml_path)
542
590
 
@@ -1,20 +1,31 @@
1
+ ## OpenStudio-HPXML v1.5.1
2
+
3
+ __New Features__
4
+ - When `Battery/Location` not provided, now defaults to garage if present, otherwise outside.
5
+ - BuildResidentialScheduleFile measure:
6
+ - Allows requesting a subset of end uses (columns) to be generated.
7
+
8
+ __Bugfixes__
9
+ - Fixes total/net electricity timeseries outputs to include battery charging/discharging energy.
10
+ - Fixes error when a non-electric water heater has jacket insulation and the UEF metric is used.
11
+
1
12
  ## OpenStudio-HPXML v1.5.0
2
13
 
3
14
  __New Features__
4
15
  - Updates to OpenStudio 3.5.0/EnergyPlus 22.2.
5
16
  - Updates to newer proposed HPXML v4.0:
6
- - **Breaking Change**: Replaces `FrameFloors/FrameFloor` with `Floors/Floor`.
17
+ - **Breaking change**: Replaces `FrameFloors/FrameFloor` with `Floors/Floor`.
7
18
  - **Breaking change**: `Floor/FloorType` (WoodFrame, StructuralInsulatedPanel, SteelFrame, or SolidConcrete) is a required input.
8
- - **Breaking Change**: All `Ducts` must now have a `SystemIdentifier`.
9
- - **Breaking Change**: Replaces `WallType/StructurallyInsulatedPanel` with `WallType/StructuralInsulatedPanel`.
19
+ - **Breaking change**: All `Ducts` must now have a `SystemIdentifier`.
20
+ - **Breaking change**: Replaces `WallType/StructurallyInsulatedPanel` with `WallType/StructuralInsulatedPanel`.
10
21
  - **Breaking change**: Replaces `SoftwareInfo/extension/SimulationControl/DaylightSaving/Enabled` with `Building/Site/TimeZone/DSTObserved`.
11
- - **Breaking Change**: Replaces `StandbyLoss` with `StandbyLoss[Units="F/hr"]/Value` for an indirect water heater.
12
- - **Breaking Change**: Replaces `BranchPipingLoopLength` with `BranchPipingLength` for a hot water recirculation system.
13
- - **Breaking Change**: Replaces `Floor/extension/OtherSpaceAboveOrBelow` with `Floor/FloorOrCeiling`.
22
+ - **Breaking change**: Replaces `StandbyLoss` with `StandbyLoss[Units="F/hr"]/Value` for an indirect water heater.
23
+ - **Breaking change**: Replaces `BranchPipingLoopLength` with `BranchPipingLength` for a hot water recirculation system.
24
+ - **Breaking change**: Replaces `Floor/extension/OtherSpaceAboveOrBelow` with `Floor/FloorOrCeiling`.
14
25
  - **Breaking change**: For PTAC with heating, replaces `HeatingSystem` of type PackagedTerminalAirConditionerHeating with `CoolingSystem/IntegratedHeating*` elements.
15
- - **Breaking Change**: Now performs full HPXML XSD schema validation (previously just limited checks); yields runtime speed improvements.
16
- - **Breaking Change**: HVAC/DHW equipment efficiencies can no longer be defaulted (e.g., based on age of equipment); they are now required.
17
- - **Breaking Change**: Deprecates ReportHPXMLOutput measure; HVAC autosized capacities & design loads moved to `results_annual.csv`.
26
+ - **Breaking change**: Now performs full HPXML XSD schema validation (previously just limited checks); yields runtime speed improvements.
27
+ - **Breaking change**: HVAC/DHW equipment efficiencies can no longer be defaulted (e.g., based on age of equipment); they are now required.
28
+ - **Breaking change**: Deprecates ReportHPXMLOutput measure; HVAC autosized capacities & design loads moved to `results_annual.csv`.
18
29
  - **Breaking change**: BuildResidentialHPXML measure: Replaces arguments using 'auto' for defaults with optional arguments of the appropriate data type.
19
30
  - Utility bill calculations:
20
31
  - **Breaking change**: Removes utility rate and PV related arguments from the ReportUtilityBills measure in lieu of HPXML file inputs.
@@ -305,7 +316,7 @@ __Bugfixes__
305
316
 
306
317
  __New Features__
307
318
  - New [Schematron](http://schematron.com) validation (EPvalidator.xml) replaces custom ruby validation (EPvalidator.rb)
308
- - **[Breaking Change]** `BuildingConstruction/ResidentialFacilityType` ("single-family detached", "single-family attached", "apartment unit", or "manufactured home") is a required input
319
+ - **[Breaking change]** `BuildingConstruction/ResidentialFacilityType` ("single-family detached", "single-family attached", "apartment unit", or "manufactured home") is a required input
309
320
  - Ability to model shared systems for Attached/Multifamily dwelling units
310
321
  - Shared HVAC systems (cooling towers, chillers, central boilers, water loop heat pumps, fan coils, ground source heat pumps on shared hydronic circulation loops)
311
322
  - Shared water heaters serving either A) multiple dwelling units' service hot water or B) a shared laundry/equipment room, as well as hot water recirculation systems
@@ -313,7 +324,7 @@ __New Features__
313
324
  - Shared hot water recirculation systems
314
325
  - Shared ventilation systems (optionally with preconditioning equipment and recirculation)
315
326
  - Shared PV systems
316
- - **[Breaking Change]** Appliances located in MF spaces (i.e., "other") must now be specified in more detail (i.e., "other heated space", "other non-freezing space", "other multifamily buffer space", or "other housing unit")
327
+ - **[Breaking change]** Appliances located in MF spaces (i.e., "other") must now be specified in more detail (i.e., "other heated space", "other non-freezing space", "other multifamily buffer space", or "other housing unit")
317
328
  - Enclosure
318
329
  - New optional inputs: `Roof/RoofType`, `Wall/Siding`, and `RimJoist/Siding`
319
330
  - New optional inputs: `Skylight/InteriorShading/SummerShadingCoefficient` and `Skylight/InteriorShading/SummerShadingCoefficient`
@@ -321,7 +332,7 @@ __New Features__
321
332
  - New optional input to specify presence of flue/chimney, which results in increased infiltration
322
333
  - Allows adobe wall type
323
334
  - Allows `AirInfiltrationMeasurement/HousePressure` to be any value (previously required to be 50 Pa)
324
- - **[Breaking Change]** `Roof/RadiantBarrierGrade` input now required when there is a radiant barrier
335
+ - **[Breaking change]** `Roof/RadiantBarrierGrade` input now required when there is a radiant barrier
325
336
  - HVAC
326
337
  - Adds optional high-level HVAC autosizing controls
327
338
  - `AllowIncreasedFixedCapacities`: Describes how HVAC equipment with fixed capacities are handled. If true, the maximum of the user-specified fixed capacity and the heating/cooling design load will be used to reduce potential for unmet loads. Defaults to false.
@@ -333,11 +344,11 @@ __New Features__
333
344
  - Appliances & Plug Loads
334
345
  - Allows _multiple_ `Refrigerator` and `Freezer`
335
346
  - Allows `Pool`, `HotTub`, `PlugLoad` of type "electric vehicle charging" and "well pump", and `FuelLoad` of type "grill", "lighting", and "fireplace"
336
- - **[Breaking Change]** "other" and "TV other" plug loads now required
347
+ - **[Breaking change]** "other" and "TV other" plug loads now required
337
348
  - Lighting
338
349
  - Allows lighting schedules and holiday lighting
339
- - **[Breaking Change]** For hydronic distributions, `HydronicDistributionType` is now required
340
- - **[Breaking Change]** For DSE distributions, `AnnualHeatingDistributionSystemEfficiency` and `AnnualCoolingDistributionSystemEfficiency` are both always required
350
+ - **[Breaking change]** For hydronic distributions, `HydronicDistributionType` is now required
351
+ - **[Breaking change]** For DSE distributions, `AnnualHeatingDistributionSystemEfficiency` and `AnnualCoolingDistributionSystemEfficiency` are both always required
341
352
  - Allows more HPXML fuel types to be used for HVAC, water heating, appliances, etc.
342
353
  - New inputs to define Daylight Saving period; defaults to enabled
343
354
  - Adds more reporting of warnings/errors to run.log
@@ -353,7 +364,7 @@ __Bugfixes__
353
364
  __New Features__
354
365
  - Dwelling units of single-family attached/multifamily buildings:
355
366
  - Adds new generic space types "other heated space", "other multifamily buffer space", and "other non-freezing space" for surface `ExteriorAdjacentTo` elements. "other housing unit", i.e. adiabatic surfaces, was already supported.
356
- - **[Breaking Change]** For `FrameFloors`, replaces "other housing unit above" and "other housing unit below" enumerations with "other housing unit". All four "other ..." spaces must have an `extension/OtherSpaceAboveOrBelow` property set to either "above" or "below".
367
+ - **[Breaking change]** For `FrameFloors`, replaces "other housing unit above" and "other housing unit below" enumerations with "other housing unit". All four "other ..." spaces must have an `extension/OtherSpaceAboveOrBelow` property set to either "above" or "below".
357
368
  - Allows ducts and water heaters to be located in all "other ..." spaces.
358
369
  - Allows all appliances to be located in "other", in which internal gains are neglected.
359
370
  - Allows `Fireplace` and `FloorFurnace` for heating system types.
@@ -364,15 +375,15 @@ __New Features__
364
375
  - Allows user-specified `Refrigerator` and `CookingRange` schedules to be provided.
365
376
  - HVAC capacity elements are no longer required; if not provided, ACCA Manual J autosizing calculations will be used (-1 can continue to be used for capacity elements but is discouraged).
366
377
  - Duct locations/areas can be defaulted by specifying supply/return `Duct` elements without `DuctSurfaceArea` and `DuctLocation`. `HVACDistribution/DistributionSystemType/AirDistribution/NumberofReturnRegisters` can be optionally provided to inform the default duct area calculations.
367
- - **[Breaking Change]** Lighting inputs now use `LightingType[LightEmittingDiode | CompactFluorescent | FluorescentTube]` instead of `ThirdPartyCertification="ERI Tier I" or ThirdPartyCertification="ERI Tier II"`.
368
- - **[Breaking Change]** `HVACDistribution/ConditionedFloorAreaServed` is now required for air distribution systems.
369
- - **[Breaking Change]** Infiltration and attic ventilation specified using natural air changes per hour now uses `ACHnatural` instead of `extension/ConstantACHnatural`.
370
- - **[Breaking Change]** The optional `PerformanceAdjustment` input for instantaneous water heaters is now treated as a performance multiplier (e.g., 0.92) instead of derate (e.g., 0.08).
378
+ - **[Breaking change]** Lighting inputs now use `LightingType[LightEmittingDiode | CompactFluorescent | FluorescentTube]` instead of `ThirdPartyCertification="ERI Tier I" or ThirdPartyCertification="ERI Tier II"`.
379
+ - **[Breaking change]** `HVACDistribution/ConditionedFloorAreaServed` is now required for air distribution systems.
380
+ - **[Breaking change]** Infiltration and attic ventilation specified using natural air changes per hour now uses `ACHnatural` instead of `extension/ConstantACHnatural`.
381
+ - **[Breaking change]** The optional `PerformanceAdjustment` input for instantaneous water heaters is now treated as a performance multiplier (e.g., 0.92) instead of derate (e.g., 0.08).
371
382
  - Adds ASHRAE 140 Class II test files.
372
383
  - SimulationOutputReport reporting measure:
373
384
  - New optional timeseries outputs: airflows (e.g., infiltration, mechanical ventilation, natural ventilation, whole house fan) and weather (e.g., temperatures, wind speed, solar).
374
385
  - Timeseries frequency can now be set to 'none' as an alternative to setting all include_timeseries_foo variables to false.
375
- - **[Breaking Change]** Renames "Wood" to "Wood Cord" to better distinguish from "Wood Pellets".
386
+ - **[Breaking change]** Renames "Wood" to "Wood Cord" to better distinguish from "Wood Pellets".
376
387
  - Modeling improvements:
377
388
  - Improved calculation for infiltration height
378
389
  - Infiltration & mechanical ventilation now combined using ASHRAE 62.2 Normative Appendix C.
@@ -398,10 +409,10 @@ __Bugfixes__
398
409
  ## OpenStudio-HPXML v0.9.0 Beta
399
410
 
400
411
  __New Features__
401
- - **[Breaking Change]** Updates to OpenStudio v3.0.0 and EnergyPlus 9.3
412
+ - **[Breaking change]** Updates to OpenStudio v3.0.0 and EnergyPlus 9.3
402
413
  - Numerous HPXML inputs are now optional with built-in defaulting, particularly for water heating, appliances, and PV. Set the `debug` argument to true to output a in.xml HPXML file with defaults applied for inspection. See the documentation for defaulting equations/assumptions/references.
403
- - **[Breaking Change]** If clothes washer efficiency inputs are provided, `LabelUsage` is now required.
404
- - **[Breaking Change]** If dishwasher efficiency inputs are provided, `LabelElectricRate`, `LabelGasRate`, `LabelAnnualGasCost`, and `LabelUsage` are now required.
414
+ - **[Breaking change]** If clothes washer efficiency inputs are provided, `LabelUsage` is now required.
415
+ - **[Breaking change]** If dishwasher efficiency inputs are provided, `LabelElectricRate`, `LabelGasRate`, `LabelAnnualGasCost`, and `LabelUsage` are now required.
405
416
  - Adds optional specification of simulation controls including timestep and begin/end dates.
406
417
  - Adds optional `extension/UsageMultiplier` inputs for appliances, plug loads, lighting, and water fixtures. Can be used to, e.g., reflect high/low usage occupants.
407
418
  - Adds ability to model a dehumidifier.
@@ -409,9 +420,9 @@ __New Features__
409
420
  - Improved desuperheater model; desuperheater can now be connected to heat pump water heaters.
410
421
  - Updated clothes washer/dryer and dishwasher models per ANSI/RESNET/ICC 301-2019 Addendum A.
411
422
  - Solar thermal systems modeled with `SolarFraction` can now be connected to combi water heating systems.
412
- - **[Breaking Change]** Replaces optional `epw_output_path` and `osm_output_path` arguments with a single optional `output_dir` argument; adds an optional `debug` argument.
413
- - **[Breaking Change]** Replaces optional `BuildingConstruction/extension/FractionofOperableWindowArea` with optional `Window/FractionOperable`.
414
- - **[Breaking Change]** Replaces optional `extension/EPWFileName` with optional `extension/EPWFilePath` to allow absolute paths to be provided as an alternative to just the file name.
423
+ - **[Breaking change]** Replaces optional `epw_output_path` and `osm_output_path` arguments with a single optional `output_dir` argument; adds an optional `debug` argument.
424
+ - **[Breaking change]** Replaces optional `BuildingConstruction/extension/FractionofOperableWindowArea` with optional `Window/FractionOperable`.
425
+ - **[Breaking change]** Replaces optional `extension/EPWFileName` with optional `extension/EPWFilePath` to allow absolute paths to be provided as an alternative to just the file name.
415
426
  - Replaces REXML xml library with Oga for better runtime performance.
416
427
  - Additional error-checking.
417
428
  - SimulationOutputReport reporting measure:
@@ -429,7 +440,7 @@ __Bugfixes__
429
440
 
430
441
  ## OpenStudio-HPXML v0.8.0 Beta
431
442
 
432
- __Breaking Changes__
443
+ __Breaking changes__
433
444
  - Weather cache files are now in .csv instead of .cache format.
434
445
  - `extension/StandbyLoss` changed to `StandbyLoss` for indirect water heaters.
435
446
  - `Site/extension/DisableNaturalVentilation` changed to `BuildingConstruction/extension/FractionofOperableWindowArea` for more granularity.