urbanopt-cli 0.9.0 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
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.