urbanopt-reporting 0.4.3 → 0.6.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -1
- data/LICENSE.md +17 -17
- data/doc_templates/LICENSE.md +17 -17
- data/doc_templates/copyright_erb.txt +2 -2
- data/doc_templates/copyright_js.txt +2 -2
- data/doc_templates/copyright_ruby.txt +1 -1
- data/docs/package-lock.json +15720 -1410
- data/lib/measures/.rubocop.yml +4 -2
- data/lib/measures/default_feature_reports/measure.rb +242 -36
- data/lib/measures/export_modelica_loads/measure.rb +2 -1
- data/lib/measures/export_time_series_modelica/measure.rb +58 -59
- data/lib/measures/export_time_series_modelica/resources/os_lib_helper_methods.rb +3 -5
- data/lib/urbanopt/reporting/default_reports/construction_cost.rb +2 -1
- data/lib/urbanopt/reporting/default_reports/date.rb +2 -1
- data/lib/urbanopt/reporting/default_reports/distributed_generation.rb +24 -6
- data/lib/urbanopt/reporting/default_reports/end_use.rb +1 -1
- data/lib/urbanopt/reporting/default_reports/end_uses.rb +2 -1
- data/lib/urbanopt/reporting/default_reports/extension.rb +1 -1
- data/lib/urbanopt/reporting/default_reports/feature_report.rb +9 -8
- data/lib/urbanopt/reporting/default_reports/generator.rb +1 -2
- data/lib/urbanopt/reporting/default_reports/location.rb +2 -1
- data/lib/urbanopt/reporting/default_reports/logger.rb +2 -2
- data/lib/urbanopt/reporting/default_reports/power_distribution.rb +22 -6
- data/lib/urbanopt/reporting/default_reports/program.rb +2 -1
- data/lib/urbanopt/reporting/default_reports/reporting_period.rb +47 -7
- data/lib/urbanopt/reporting/default_reports/scenario_power_distribution.rb +148 -0
- data/lib/urbanopt/reporting/default_reports/scenario_report.rb +20 -14
- data/lib/urbanopt/reporting/default_reports/schema/scenario_csv_columns.txt +24 -0
- data/lib/urbanopt/reporting/default_reports/schema/scenario_schema.json +265 -6
- data/lib/urbanopt/reporting/default_reports/solar_pv.rb +42 -3
- data/lib/urbanopt/reporting/default_reports/storage.rb +1 -1
- data/lib/urbanopt/reporting/default_reports/thermal_storage.rb +1 -1
- data/lib/urbanopt/reporting/default_reports/timeseries_csv.rb +2 -1
- data/lib/urbanopt/reporting/default_reports/validator.rb +1 -1
- data/lib/urbanopt/reporting/default_reports/wind.rb +11 -2
- data/lib/urbanopt/reporting/default_reports.rb +1 -1
- data/lib/urbanopt/reporting/derived_extension.rb +1 -1
- data/lib/urbanopt/reporting/version.rb +2 -2
- data/lib/urbanopt/reporting.rb +1 -1
- data/urbanopt-reporting-gem.gemspec +3 -4
- metadata +16 -15
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -40,11 +40,10 @@
|
|
40
40
|
|
41
41
|
require 'erb'
|
42
42
|
|
43
|
-
|
44
43
|
# This measure is originally from https://github.com/urbanopt/DES_HVAC
|
45
44
|
# start the measure
|
46
45
|
class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
47
|
-
Dir[File.dirname(__FILE__)
|
46
|
+
Dir["#{File.dirname(__FILE__)}/resources/*.rb"].sort.each { |file| require file }
|
48
47
|
include OsLib_HelperMethods
|
49
48
|
# human readable name
|
50
49
|
def name
|
@@ -75,12 +74,12 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
75
74
|
hhw_loop_name.setDefaultValue('hot')
|
76
75
|
args << hhw_loop_name
|
77
76
|
|
78
|
-
|
77
|
+
chw_loop_name = OpenStudio::Measure::OSArgument.makeStringArgument('chw_loop_name', true)
|
79
78
|
chw_loop_name.setDisplayName('Name or Partial Name of Chilled Water Loop, non-case-sensitive')
|
80
79
|
chw_loop_name.setDefaultValue('chilled')
|
81
80
|
args << chw_loop_name
|
82
81
|
|
83
|
-
|
82
|
+
dec_places_mass_flow = OpenStudio::Measure::OSArgument.makeIntegerArgument('dec_places_mass_flow', true)
|
84
83
|
dec_places_mass_flow.setDisplayName('Number of Decimal Places to Round Mass Flow Rate')
|
85
84
|
dec_places_mass_flow.setDescription('Number of decimal places to which mass flow rate will be rounded')
|
86
85
|
dec_places_mass_flow.setDefaultValue(3)
|
@@ -113,11 +112,11 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
113
112
|
# use the built-in error checking
|
114
113
|
return false unless runner.validateUserArguments(arguments(model), user_arguments)
|
115
114
|
|
116
|
-
|
115
|
+
# #Read in argumetns related to variables for output requests
|
117
116
|
hhw_loop_name = runner.getStringArgumentValue('hhw_loop_name', user_arguments)
|
118
117
|
chw_loop_name = runner.getStringArgumentValue('chw_loop_name', user_arguments)
|
119
118
|
|
120
|
-
#Identify key names for output variables.
|
119
|
+
# Identify key names for output variables.
|
121
120
|
plantloops = model.getPlantLoops
|
122
121
|
|
123
122
|
selected_plant_loops = []
|
@@ -128,19 +127,19 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
128
127
|
reporting_frequency = 'timestep'
|
129
128
|
|
130
129
|
plantloops.each do |plantLoop|
|
131
|
-
|
130
|
+
log "plant loop name #{plantLoop.name.get}"
|
132
131
|
if plantLoop.name.get.to_s.downcase.include? chw_loop_name.to_s
|
133
|
-
#Extract plant loop information
|
134
|
-
selected_plant_loops[0]=plantLoop
|
132
|
+
# Extract plant loop information
|
133
|
+
selected_plant_loops[0] = plantLoop
|
135
134
|
key_value_chw_outlet = selected_plant_loops[0].demandOutletNode.name.to_s
|
136
135
|
key_value_chw_inlet = selected_plant_loops[0].demandInletNode.name.to_s
|
137
136
|
result << OpenStudio::IdfObject.load("Output:Variable,#{key_value_chw_outlet},#{variable_name2},timestep;").get
|
138
137
|
result << OpenStudio::IdfObject.load("Output:Variable,#{key_value_chw_inlet},#{variable_name2},timestep;").get
|
139
138
|
result << OpenStudio::IdfObject.load("Output:Variable,#{key_value_chw_outlet},#{variable_name1},timestep;").get
|
140
139
|
end
|
141
|
-
if plantLoop.name.get.to_s.downcase.include?
|
142
|
-
#Extract plant loop information
|
143
|
-
selected_plant_loops[1]=plantLoop
|
140
|
+
if plantLoop.name.get.to_s.downcase.include?(hhw_loop_name.to_s) && !plantLoop.name.get.to_s.downcase.include?('service') && !plantLoop.name.get.to_s.downcase.include?('domestic')
|
141
|
+
# Extract plant loop information
|
142
|
+
selected_plant_loops[1] = plantLoop
|
144
143
|
key_value_hhw_outlet = selected_plant_loops[1].demandOutletNode.name.to_s
|
145
144
|
key_value_hhw_inlet = selected_plant_loops[1].demandInletNode.name.to_s
|
146
145
|
result << OpenStudio::IdfObject.load("Output:Variable,#{key_value_hhw_outlet},#{variable_name2},timestep;").get
|
@@ -153,7 +152,7 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
153
152
|
result << OpenStudio::IdfObject.load('Output:Variable,,Site Outdoor Air Drybulb Temperature,hourly;').get
|
154
153
|
result << OpenStudio::IdfObject.load('Output:Variable,,Site Outdoor Air Relative Humidity,hourly;').get
|
155
154
|
result << OpenStudio::IdfObject.load('Output:Meter,Cooling:Electricity,hourly;').get
|
156
|
-
|
155
|
+
result << OpenStudio::IdfObject.load('Output:Meter,Electricity:Facility,timestep;').get # #Using this for data at timestep interval
|
157
156
|
result << OpenStudio::IdfObject.load('Output:Meter,Heating:Electricity,hourly;').get
|
158
157
|
result << OpenStudio::IdfObject.load('Output:Meter,Heating:NaturalGas,hourly;').get
|
159
158
|
result << OpenStudio::IdfObject.load('Output:Meter,InteriorLights:Electricity,hourly;').get
|
@@ -171,15 +170,15 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
171
170
|
result
|
172
171
|
end
|
173
172
|
|
174
|
-
def extract_timeseries_into_matrix(sqlfile, data, variable_name, str, key_value = nil, default_if_empty = 0,dec_places, timestep)
|
173
|
+
def extract_timeseries_into_matrix(sqlfile, data, variable_name, str, key_value = nil, default_if_empty = 0, dec_places, timestep)
|
175
174
|
log "Executing query for #{variable_name}"
|
176
|
-
#column_name = variable_name
|
175
|
+
# column_name = variable_name
|
177
176
|
if key_value
|
178
177
|
ts = sqlfile.timeSeries('RUN PERIOD 1', 'Zone Timestep', variable_name, key_value)
|
179
|
-
#column_name += "_#{key_value}"
|
180
|
-
|
178
|
+
# column_name += "_#{key_value}"
|
179
|
+
column_name = str
|
181
180
|
else
|
182
|
-
#ts = sqlfile.timeSeries('RUN PERIOD 1', 'Hourly', variable_name)
|
181
|
+
# ts = sqlfile.timeSeries('RUN PERIOD 1', 'Hourly', variable_name)
|
183
182
|
ts = sqlfile.timeSeries('RUN PERIOD 1', 'Zone Timestep', variable_name)
|
184
183
|
end
|
185
184
|
log 'Iterating over timeseries'
|
@@ -201,16 +200,16 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
201
200
|
# end
|
202
201
|
|
203
202
|
quick_proc = ts.values.to_s.split(',')
|
204
|
-
quick_proc[0]=quick_proc[0].split('(', 2).last #cleanup necessary to remove opening paren
|
205
|
-
quick_proc=quick_proc.map(&:to_f)
|
203
|
+
quick_proc[0] = quick_proc[0].split('(', 2).last # cleanup necessary to remove opening paren
|
204
|
+
quick_proc = quick_proc.map(&:to_f)
|
206
205
|
x = 0
|
207
206
|
len = quick_proc.length
|
208
|
-
|
209
|
-
while
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
207
|
+
log "quick proc #{quick_proc}"
|
208
|
+
while x < len # Round to the # of decimal places specified
|
209
|
+
quick_proc[x] = (quick_proc[x]).round(dec_places)
|
210
|
+
x += 1
|
211
|
+
end
|
212
|
+
quick_proc = quick_proc.map(&:to_s)
|
214
213
|
|
215
214
|
# the first and last have some cleanup items because of the Vector method
|
216
215
|
quick_proc[0] = quick_proc[0].gsub(/^.*\(/, '')
|
@@ -232,7 +231,7 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
232
231
|
log "Finished extracting #{variable_name}"
|
233
232
|
end
|
234
233
|
|
235
|
-
def create_new_variable_sum(data, new_var_name, include_str, options=nil)
|
234
|
+
def create_new_variable_sum(data, new_var_name, include_str, options = nil)
|
236
235
|
var_info = {
|
237
236
|
name: new_var_name,
|
238
237
|
var_indexes: []
|
@@ -285,16 +284,18 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
285
284
|
|
286
285
|
# lookup and replace argument values from upstream measures
|
287
286
|
if args['use_upstream_args'] == true
|
288
|
-
args.each do |arg,value|
|
287
|
+
args.each do |arg, value|
|
289
288
|
next if arg == 'use_upstream_args' # this argument should not be changed
|
289
|
+
|
290
290
|
value_from_osw = OsLib_HelperMethods.check_upstream_measure_for_arg(runner, arg)
|
291
291
|
if !value_from_osw.empty?
|
292
292
|
runner.registerInfo("Replacing argument named #{arg} from current measure with a value of #{value_from_osw[:value]} from #{value_from_osw[:measure_name]}.")
|
293
293
|
new_val = value_from_osw[:value]
|
294
294
|
# TODO: make code to handle non strings more robust. check_upstream_measure_for_arg could pass back the argument type
|
295
|
-
|
295
|
+
case arg
|
296
|
+
when 'hhw_loop_name'
|
296
297
|
args[arg] = new_val.to_s
|
297
|
-
|
298
|
+
when 'chw_loop_name'
|
298
299
|
args[arg] = new_val.to_s
|
299
300
|
else
|
300
301
|
args[arg] = new_val
|
@@ -314,8 +315,8 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
314
315
|
end
|
315
316
|
model = model.get
|
316
317
|
|
317
|
-
timesteps_per_hour=model.getTimestep.numberOfTimestepsPerHour.to_i
|
318
|
-
timestep=60/timesteps_per_hour #timestep in minutes
|
318
|
+
timesteps_per_hour = model.getTimestep.numberOfTimestepsPerHour.to_i
|
319
|
+
timestep = 60 / timesteps_per_hour # timestep in minutes
|
319
320
|
|
320
321
|
sqlFile = runner.lastEnergyPlusSqlFile
|
321
322
|
if sqlFile.empty?
|
@@ -342,7 +343,7 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
342
343
|
ts = sqlFile.timeSeries('RUN PERIOD 1', 'Zone Timestep', attribute_name)
|
343
344
|
if ts.empty?
|
344
345
|
runner.registerError("This feature does not have the attribute '#{attribute_name}' to enable this measure to work." \
|
345
|
-
|
346
|
+
'To resolve, simulate a building with electricity or remove this measure from your workflow.')
|
346
347
|
else
|
347
348
|
ts = ts.first
|
348
349
|
dt_base = nil
|
@@ -357,7 +358,7 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
357
358
|
dt.date.dayOfWeek.value,
|
358
359
|
dt.time.hours,
|
359
360
|
dt.time.minutes,
|
360
|
-
dt_current.to_time.to_i - dt_base.to_time.to_i + timestep*60
|
361
|
+
dt_current.to_time.to_i - dt_base.to_time.to_i + timestep * 60
|
361
362
|
]
|
362
363
|
end
|
363
364
|
end
|
@@ -367,52 +368,51 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
367
368
|
selected_plant_loops = []
|
368
369
|
i = 0
|
369
370
|
|
370
|
-
key_var={}
|
371
|
+
key_var = {}
|
371
372
|
|
372
373
|
plantloops.each do |plantLoop|
|
373
374
|
if plantLoop.name.get.to_s.downcase.include? chw_loop_name.to_str
|
374
|
-
#Extract plant loop information
|
375
|
-
|
375
|
+
# Extract plant loop information
|
376
|
+
selected_plant_loops[0] = plantLoop
|
376
377
|
end
|
377
378
|
if plantLoop.name.get.to_s.downcase.include? hhw_loop_name.to_str
|
378
|
-
|
379
|
-
|
379
|
+
# Get plant loop information
|
380
|
+
selected_plant_loops[1] = plantLoop
|
380
381
|
end
|
381
382
|
end
|
382
383
|
|
383
384
|
if !selected_plant_loops[1].nil?
|
384
|
-
#Set up variables for output
|
385
|
+
# Set up variables for output
|
385
386
|
key_value_hhw_outlet = selected_plant_loops[1].demandOutletNode.name.to_s
|
386
387
|
key_value_hhw_inlet = selected_plant_loops[1].demandInletNode.name.to_s
|
387
|
-
key_var['hhw_outlet_massflow']='massFlowRateHeating'
|
388
|
-
key_var['hhw_outlet_temp']='heatingReturnTemperature[C]'
|
389
|
-
key_var['hhw_inlet_temp']='heatingSupplyTemperature[C]'
|
390
|
-
#Extract time series
|
388
|
+
key_var['hhw_outlet_massflow'] = 'massFlowRateHeating'
|
389
|
+
key_var['hhw_outlet_temp'] = 'heatingReturnTemperature[C]'
|
390
|
+
key_var['hhw_inlet_temp'] = 'heatingSupplyTemperature[C]'
|
391
|
+
# Extract time series
|
391
392
|
extract_timeseries_into_matrix(sqlFile, rows, 'System Node Temperature', key_var['hhw_outlet_temp'], key_value_hhw_outlet, 0, dec_places_temp, timestep)
|
392
393
|
extract_timeseries_into_matrix(sqlFile, rows, 'System Node Temperature', key_var['hhw_inlet_temp'], key_value_hhw_inlet, 0, dec_places_temp, timestep)
|
393
394
|
extract_timeseries_into_matrix(sqlFile, rows, 'System Node Mass Flow Rate', key_var['hhw_outlet_massflow'], key_value_hhw_outlet, 0, dec_places_mass_flow, timestep)
|
394
395
|
else
|
395
|
-
runner.registerWarning(
|
396
|
+
runner.registerWarning('No hot water loop found. If one is expected, make sure the hot water loop name argument provides a string present in its name.')
|
396
397
|
end
|
397
398
|
|
398
399
|
if !selected_plant_loops[0].nil?
|
399
|
-
#Set up variables for outputs
|
400
|
+
# Set up variables for outputs
|
400
401
|
key_value_chw_outlet = selected_plant_loops[0].demandOutletNode.name.to_s
|
401
402
|
key_value_chw_inlet = selected_plant_loops[0].demandInletNode.name.to_s
|
402
|
-
key_var['chw_outlet_massflow']='massFlowRateCooling'
|
403
|
-
key_var['chw_outlet_temp']='ChilledWaterReturnTemperature[C]'
|
404
|
-
key_var['chw_inlet_temp']='ChilledWaterSupplyTemperature[C]'
|
405
|
-
#Extract time series
|
406
|
-
extract_timeseries_into_matrix(sqlFile, rows, 'System Node Temperature', key_var['chw_outlet_temp'], key_value_chw_outlet, 0, dec_places_temp,timestep)
|
407
|
-
extract_timeseries_into_matrix(sqlFile, rows, 'System Node Temperature', key_var['chw_inlet_temp'], key_value_chw_inlet, 0, dec_places_temp,timestep)
|
408
|
-
extract_timeseries_into_matrix(sqlFile, rows, 'System Node Mass Flow Rate', key_var['chw_outlet_massflow'], key_value_chw_outlet, 0, dec_places_mass_flow,timestep)
|
403
|
+
key_var['chw_outlet_massflow'] = 'massFlowRateCooling'
|
404
|
+
key_var['chw_outlet_temp'] = 'ChilledWaterReturnTemperature[C]'
|
405
|
+
key_var['chw_inlet_temp'] = 'ChilledWaterSupplyTemperature[C]'
|
406
|
+
# Extract time series
|
407
|
+
extract_timeseries_into_matrix(sqlFile, rows, 'System Node Temperature', key_var['chw_outlet_temp'], key_value_chw_outlet, 0, dec_places_temp, timestep)
|
408
|
+
extract_timeseries_into_matrix(sqlFile, rows, 'System Node Temperature', key_var['chw_inlet_temp'], key_value_chw_inlet, 0, dec_places_temp, timestep)
|
409
|
+
extract_timeseries_into_matrix(sqlFile, rows, 'System Node Mass Flow Rate', key_var['chw_outlet_massflow'], key_value_chw_outlet, 0, dec_places_mass_flow, timestep)
|
409
410
|
else
|
410
|
-
runner.registerWarning(
|
411
|
+
runner.registerWarning('No chilled water loop found. If one is expected, make sure the chilled water loop name argument provides a string present in its name.')
|
411
412
|
end
|
412
413
|
|
413
|
-
|
414
|
-
|
415
|
-
runner.registerWarning("No HVAC plant loops found. If one or more plant loops are expected, make sure they follow the naming conventions mentioned in the previous warnings.")
|
414
|
+
if selected_plant_loops[0].nil? && selected_plant_loops[1].nil?
|
415
|
+
runner.registerWarning('No HVAC plant loops found. If one or more plant loops are expected, make sure they follow the naming conventions mentioned in the previous warnings.')
|
416
416
|
end
|
417
417
|
|
418
418
|
if !selected_plant_loops.nil?
|
@@ -430,6 +430,5 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
430
430
|
end
|
431
431
|
end
|
432
432
|
|
433
|
-
|
434
433
|
# register the measure to be used by the application
|
435
434
|
ExportTimeSeriesLoadsCSV.new.registerWithApplication
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -358,10 +358,8 @@ module OsLib_HelperMethods
|
|
358
358
|
objectArray.each do |object|
|
359
359
|
object_LCCs = object.lifeCycleCosts
|
360
360
|
object_LCCs.each do |object_LCC|
|
361
|
-
if object_LCC.category == category
|
362
|
-
|
363
|
-
counter += object_LCC.totalCost
|
364
|
-
end
|
361
|
+
if object_LCC.category == category && (onlyYearFromStartZero == false || object_LCC.yearsFromStart == 0)
|
362
|
+
counter += object_LCC.totalCost
|
365
363
|
end
|
366
364
|
end
|
367
365
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -50,6 +50,7 @@ module URBANopt
|
|
50
50
|
##
|
51
51
|
class ConstructionCost
|
52
52
|
attr_accessor :category, :item_name, :unit_cost, :cost_units, :item_quantity, :total_cost # :nodoc:
|
53
|
+
|
53
54
|
##
|
54
55
|
# ConstructionCost class intialize all construction_cost attributes:
|
55
56
|
# +:category+ , +:item_name+ , +:unit_cost+ , +:cost_units+ , +:item_quantity+ , +:total_cost+
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -50,6 +50,7 @@ module URBANopt
|
|
50
50
|
##
|
51
51
|
class Date
|
52
52
|
attr_accessor :month, :day_of_month, :year #:nodoc:
|
53
|
+
|
53
54
|
##
|
54
55
|
# Date class intialize all date attributes:
|
55
56
|
# +:month+ , +:day_of_month+ , +:year+
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -192,6 +192,15 @@ module URBANopt
|
|
192
192
|
#
|
193
193
|
attr_accessor :probs_of_surviving_by_hour_of_the_day
|
194
194
|
|
195
|
+
##
|
196
|
+
# _String_ - Filepath of reopt assumptions file used, if known
|
197
|
+
attr_accessor :reopt_assumptions_file_path
|
198
|
+
|
199
|
+
##
|
200
|
+
# _Float_ - Annual percentage of electricity supplied by renewable sources
|
201
|
+
#
|
202
|
+
attr_accessor :annual_renewable_electricity_pct
|
203
|
+
|
195
204
|
##
|
196
205
|
# Initialize distributed generation system design and financial metrics.
|
197
206
|
#
|
@@ -206,6 +215,7 @@ module URBANopt
|
|
206
215
|
def initialize(hash = {})
|
207
216
|
hash.delete_if { |k, v| v.nil? }
|
208
217
|
|
218
|
+
@annual_renewable_electricity_pct = hash[:annual_renewable_electricity_pct]
|
209
219
|
@lcc_us_dollars = hash[:lcc_us_dollars]
|
210
220
|
@lcc_bau_us_dollars = hash[:lcc_bau_us_dollars]
|
211
221
|
@npv_us_dollars = hash[:npv_us_dollars]
|
@@ -227,6 +237,12 @@ module URBANopt
|
|
227
237
|
@probs_of_surviving_by_month = hash[:probs_of_surviving_by_month]
|
228
238
|
@probs_of_surviving_by_hour_of_the_day = hash[:probs_of_surviving_by_hour_of_the_day]
|
229
239
|
|
240
|
+
# optional
|
241
|
+
@reopt_assumptions_file_path = nil
|
242
|
+
if hash[:reopt_assumptions_file_path]
|
243
|
+
@reopt_assumptions_file_path = hash[:reopt_assumptions_file_path]
|
244
|
+
end
|
245
|
+
|
230
246
|
@total_solar_pv_kw = nil
|
231
247
|
@total_wind_kw = nil
|
232
248
|
@total_generator_kw = nil
|
@@ -234,7 +250,7 @@ module URBANopt
|
|
234
250
|
@total_storage_kwh = nil
|
235
251
|
|
236
252
|
@solar_pv = []
|
237
|
-
if hash[:solar_pv].
|
253
|
+
if hash[:solar_pv].instance_of?(Hash)
|
238
254
|
hash[:solar_pv] = [hash[:solar_pv]]
|
239
255
|
elsif hash[:solar_pv].nil?
|
240
256
|
hash[:solar_pv] = []
|
@@ -252,7 +268,7 @@ module URBANopt
|
|
252
268
|
end
|
253
269
|
|
254
270
|
@wind = []
|
255
|
-
if hash[:wind].
|
271
|
+
if hash[:wind].instance_of?(Hash)
|
256
272
|
hash[:wind] = [hash[:wind]]
|
257
273
|
elsif hash[:wind].nil?
|
258
274
|
hash[:wind] = []
|
@@ -270,7 +286,7 @@ module URBANopt
|
|
270
286
|
end
|
271
287
|
|
272
288
|
@generator = []
|
273
|
-
if hash[:generator].
|
289
|
+
if hash[:generator].instance_of?(Hash)
|
274
290
|
hash[:generator] = [hash[:generator]]
|
275
291
|
elsif hash[:generator].nil?
|
276
292
|
hash[:generator] = []
|
@@ -288,7 +304,7 @@ module URBANopt
|
|
288
304
|
end
|
289
305
|
|
290
306
|
@storage = []
|
291
|
-
if hash[:storage].
|
307
|
+
if hash[:storage].instance_of?(Hash)
|
292
308
|
hash[:storage] = [hash[:storage]]
|
293
309
|
elsif hash[:storage].nil?
|
294
310
|
hash[:storage] = []
|
@@ -363,7 +379,8 @@ module URBANopt
|
|
363
379
|
##
|
364
380
|
def to_hash
|
365
381
|
result = {}
|
366
|
-
|
382
|
+
result[:reopt_assumptions_file_path] = @reopt_assumptions_file_path if @reopt_assumptions_file_path
|
383
|
+
result[:annual_renewable_electricity_pct] = @annual_renewable_electricity_pct if @annual_renewable_electricity_pct
|
367
384
|
result[:lcc_us_dollars] = @lcc_us_dollars if @lcc_us_dollars
|
368
385
|
result[:lcc_bau_us_dollars] = @lcc_bau_us_dollars if @lcc_bau_us_dollars
|
369
386
|
result[:npv_us_dollars] = @npv_us_dollars if @npv_us_dollars
|
@@ -433,6 +450,7 @@ module URBANopt
|
|
433
450
|
# Merge a distributed generation system with a new system
|
434
451
|
##
|
435
452
|
def self.merge_distributed_generation(existing_dgen, new_dgen)
|
453
|
+
existing_dgen.annual_renewable_electricity_pct = add_values(existing_dgen.annual_renewable_electricity_pct, new_dgen.annual_renewable_electricity_pct)
|
436
454
|
existing_dgen.lcc_us_dollars = add_values(existing_dgen.lcc_us_dollars, new_dgen.lcc_us_dollars)
|
437
455
|
existing_dgen.lcc_bau_us_dollars = add_values(existing_dgen.lcc_bau_us_dollars, new_dgen.lcc_bau_us_dollars)
|
438
456
|
existing_dgen.npv_us_dollars = add_values(existing_dgen.npv_us_dollars, new_dgen.npv_us_dollars)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -50,6 +50,7 @@ module URBANopt
|
|
50
50
|
##
|
51
51
|
class EndUses
|
52
52
|
attr_accessor :electricity_kwh, :natural_gas_kwh, :propane_kwh, :fuel_oil_kwh, :other_fuels_kwh, :district_cooling_kwh, :district_heating_kwh, :water_qbft # :nodoc:
|
53
|
+
|
53
54
|
##
|
54
55
|
# EndUses class intialize end_uses(fuel type) attributes: +:electricity_kwh+ , +:natural_gas_kwh+ , +:propane_kwh+ , +:fuel_oil_kwh+ , +:other_fuels_kwh+ ,
|
55
56
|
# +:district_cooling_kwh+ , +:district_heating_kwh+ , +:water_qbft+
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -65,6 +65,7 @@ module URBANopt
|
|
65
65
|
class FeatureReport
|
66
66
|
attr_accessor :id, :name, :directory_name, :feature_type, :timesteps_per_hour, :simulation_status,
|
67
67
|
:timeseries_csv, :location, :program, :design_parameters, :construction_costs, :reporting_periods, :distributed_generation, :power_distribution, :thermal_storage # :nodoc:
|
68
|
+
|
68
69
|
##
|
69
70
|
# Each FeatureReport object corresponds to a single Feature.
|
70
71
|
##
|
@@ -254,15 +255,15 @@ module URBANopt
|
|
254
255
|
# create feature reports directory
|
255
256
|
Dir.mkdir(results_dir_path) unless Dir.exist?(File.join(@directory_name, 'feature_reports'))
|
256
257
|
|
257
|
-
@timeseries_csv.path = File.join(@directory_name, 'feature_reports', file_name
|
258
|
+
@timeseries_csv.path = File.join(@directory_name, 'feature_reports', "#{file_name}.csv")
|
258
259
|
FileUtils.mkdir_p File.dirname(@timeseries_csv.path)
|
259
260
|
@timeseries_csv.save_data
|
260
261
|
|
261
|
-
## save json
|
262
|
+
## save json report
|
262
263
|
# feature_hash
|
263
264
|
feature_hash = to_hash
|
264
265
|
|
265
|
-
json_name_path = File.join(results_dir_path, file_name
|
266
|
+
json_name_path = File.join(results_dir_path, "#{file_name}.json")
|
266
267
|
|
267
268
|
File.open(json_name_path, 'w') do |f|
|
268
269
|
f.puts JSON.pretty_generate(feature_hash)
|
@@ -277,7 +278,7 @@ module URBANopt
|
|
277
278
|
if !old_timeseries_path.nil?
|
278
279
|
@timeseries_csv.path = old_timeseries_path
|
279
280
|
else
|
280
|
-
@timeseries_csv.path = File.join(@directory_name, file_name
|
281
|
+
@timeseries_csv.path = File.join(@directory_name, "#{file_name}.csv")
|
281
282
|
end
|
282
283
|
|
283
284
|
return true
|
@@ -312,7 +313,7 @@ module URBANopt
|
|
312
313
|
# feature_hash
|
313
314
|
feature_hash = to_hash
|
314
315
|
|
315
|
-
json_name_path = File.join(results_dir_path, file_name
|
316
|
+
json_name_path = File.join(results_dir_path, "#{file_name}.json")
|
316
317
|
|
317
318
|
File.open(json_name_path, 'w') do |f|
|
318
319
|
f.puts JSON.pretty_generate(feature_hash)
|
@@ -327,7 +328,7 @@ module URBANopt
|
|
327
328
|
|
328
329
|
##
|
329
330
|
# Saves the 'default_feature_report.csv' file to the results directory
|
330
|
-
# This method only copies the CSV feature reports from the folder generated by the reporting measure
|
331
|
+
# This method only copies the CSV feature reports from the folder generated by the reporting measure
|
331
332
|
# (<meausure number>_default_feature_reports/) to the new feature_reports/ folder
|
332
333
|
##
|
333
334
|
# [parameters]:
|
@@ -347,7 +348,7 @@ module URBANopt
|
|
347
348
|
# copy the CSV report to the new feature_reports folder
|
348
349
|
directory_folders.each do |f|
|
349
350
|
if f.include? '_default_feature_reports'
|
350
|
-
FileUtils.cp(File.join(f, 'default_feature_reports.csv'), File.join(results_dir_path, @file_name
|
351
|
+
FileUtils.cp(File.join(f, 'default_feature_reports.csv'), File.join(results_dir_path, "#{@file_name}.csv"))
|
351
352
|
end
|
352
353
|
end
|
353
354
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -80,7 +80,6 @@ module URBANopt
|
|
80
80
|
result = {}
|
81
81
|
|
82
82
|
result[:size_kw] = @size_kw if @size_kw
|
83
|
-
|
84
83
|
return result
|
85
84
|
end
|
86
85
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -50,6 +50,7 @@ module URBANopt
|
|
50
50
|
##
|
51
51
|
class Location
|
52
52
|
attr_accessor :latitude_deg, :longitude_deg, :surface_elevation_ft, :weather_filename #:nodoc:
|
53
|
+
|
53
54
|
##
|
54
55
|
# Location class initialize location attributes: +:latitude_deg+ , +:longitude_deg+ , +:surface_elevation_ft+ , +:weather_filename+
|
55
56
|
##
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -43,7 +43,7 @@ require 'logger'
|
|
43
43
|
module URBANopt
|
44
44
|
module Reporting
|
45
45
|
module DefaultReports
|
46
|
-
@@logger = Logger.new(
|
46
|
+
@@logger = Logger.new($stdout)
|
47
47
|
##
|
48
48
|
# Definining class variable "@@logger" to log errors, info and warning messages.
|
49
49
|
def self.logger
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -50,10 +50,12 @@ module URBANopt
|
|
50
50
|
# power_distributio include eletrical power distribution systems information.
|
51
51
|
##
|
52
52
|
class PowerDistribution
|
53
|
-
attr_accessor :under_voltage_hours, :over_voltage_hours
|
53
|
+
attr_accessor :under_voltage_hours, :over_voltage_hours, :nominal_capacity,
|
54
|
+
:reactance_resistance_ratio, :nominal_voltage, :max_power_kw, :max_reactive_power_kvar # :nodoc:
|
55
|
+
|
54
56
|
##
|
55
|
-
#
|
56
|
-
# +:under_voltage_hours+ , +:over_voltage_hours+
|
57
|
+
# PowerDistribution class initialize all power_distribution attributes:
|
58
|
+
# +:under_voltage_hours+ , +:over_voltage_hours+, +:nominal_capacity+, +:reactance_resistance_ratio+
|
57
59
|
##
|
58
60
|
# [parameters:]
|
59
61
|
# +hash+ - _Hash_ - A hash which may contain a deserialized power_distribution.
|
@@ -64,7 +66,11 @@ module URBANopt
|
|
64
66
|
|
65
67
|
@under_voltage_hours = hash[:under_voltage_hours]
|
66
68
|
@over_voltage_hours = hash[:over_voltage_hours]
|
67
|
-
|
69
|
+
@nominal_capacity = hash[:nominal_capacity]
|
70
|
+
@reactance_resistance_ratio = hash[:reactance_resistance_ratio]
|
71
|
+
@nominal_voltage = hash[:nominal_voltage] # in V
|
72
|
+
@max_power_kw = hash[:max_power_kw]
|
73
|
+
@max_reactive_power_kvar = hash[:max_reactive_power_kvar]
|
68
74
|
# initialize class variables @@validator and @@schema
|
69
75
|
@@validator ||= Validator.new
|
70
76
|
@@schema ||= @@validator.schema
|
@@ -77,6 +83,11 @@ module URBANopt
|
|
77
83
|
hash = {}
|
78
84
|
hash[:under_voltage_hours] = nil
|
79
85
|
hash[:over_voltage_hours] = nil
|
86
|
+
hash[:nominal_capacity] = nil
|
87
|
+
hash[:reactance_resistance_ratio] = nil
|
88
|
+
hash[:nominal_voltage] = nil
|
89
|
+
hash[:max_power_kw] = nil
|
90
|
+
hash[:max_reactive_power_kvar] = nil
|
80
91
|
|
81
92
|
return hash
|
82
93
|
end
|
@@ -91,6 +102,11 @@ module URBANopt
|
|
91
102
|
result = {}
|
92
103
|
result[:under_voltage_hours] = @under_voltage_hours if @under_voltage_hours
|
93
104
|
result[:over_voltage_hours] = @over_voltage_hours if @over_voltage_hours
|
105
|
+
result[:nominal_capacity] = @nominal_capacity if @nominal_capacity
|
106
|
+
result[:reactance_resistance_ratio] = @reactance_resistance_ratio if @reactance_resistance_ratio
|
107
|
+
result[:nominal_voltage] = @nominal_voltage if @nominal_voltage
|
108
|
+
result[:max_power_kw] = @max_power_kw if @max_power_kw
|
109
|
+
result[:max_reactive_power_kvar] = @max_reactive_power_kvar if @max_reactive_power_kvar
|
94
110
|
|
95
111
|
# validate power_distribution properties against schema
|
96
112
|
if @@validator.validate(@@schema[:definitions][:PowerDistribution][:properties], result).any?
|
@@ -104,7 +120,7 @@ module URBANopt
|
|
104
120
|
# Merges muliple power distribution results together.
|
105
121
|
##
|
106
122
|
# +new_costs+ - _Array_ - An array of ConstructionCost objects.
|
107
|
-
def
|
123
|
+
def merge_power_distribution
|
108
124
|
# method to be developed for any attributes to be aggregated or merged
|
109
125
|
end
|
110
126
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt™, Copyright (c) 2019-
|
2
|
+
# URBANopt™, Copyright (c) 2019-2022, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -56,6 +56,7 @@ module URBANopt
|
|
56
56
|
:maximum_number_of_parking_stories_above_ground, :number_of_residential_units, :building_types, :building_type, :maximum_occupancy,
|
57
57
|
:area_sqft, :window_area_sqft, :north_window_area_sqft, :south_window_area_sqft, :east_window_area_sqft, :west_window_area_sqft, :wall_area_sqft, :roof_area_sqft, :equipment_roof_area_sqft,
|
58
58
|
:photovoltaic_roof_area_sqft, :available_roof_area_sqft, :total_roof_area_sqft, :orientation_deg, :aspect_ratio, :total_construction_cost_dollar # :nodoc:
|
59
|
+
|
59
60
|
# Program class initialize building program attributes: +:site_area_sqft+ , +:floor_area_sqft+ , +:conditioned_area_sqft+ , +:unconditioned_area_sqft+ ,
|
60
61
|
# +:footprint_area_sqft+ , +:maximum_roof_height_ft, +:maximum_number_of_stories+ , +:maximum_number_of_stories_above_ground+ , +:parking_area_sqft+ ,
|
61
62
|
# +:number_of_parking_spaces+ , +:number_of_parking_spaces_charging+ , +:parking_footprint_area_sqft+ , +:maximum_parking_height_ft+ , +:maximum_number_of_parking_stories+ ,
|