diff --git a/.travis.yml b/.travis.yml index d1bf021e..68901638 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,11 +61,13 @@ jobs: - $SH "bundle exec rspec spec/tests/translator_scenario_simulations_spec.rb" name: "Translator Scenario Simulation Spec" - script: + - $SH "bundle exec rspec spec/tests/report_spec.rb" + - $SH "bundle exec rspec spec/tests/utility_spec.rb" - $SH "bundle exec rspec spec/tests/scenario_spec.rb" - $SH "bundle exec rspec spec/tests/time_series_spec.rb" - $SH "bundle exec rspec spec/tests/resource_use_spec.rb" - $SH "bundle exec rspec spec/tests/all_resource_total_spec.rb" - name: "Scenario Related Specs" + name: "Report and Scenario Related Specs" - script: - $SH "bundle exec rspec spec/tests/workflow_maker_spec.rb" name: "WorkflowMaker Spec" diff --git a/lib/buildingsync/all_resource_total.rb b/lib/buildingsync/all_resource_total.rb index 47d930cd..55bc5979 100644 --- a/lib/buildingsync/all_resource_total.rb +++ b/lib/buildingsync/all_resource_total.rb @@ -38,10 +38,12 @@ # ******************************************************************************* module BuildingSync - # ResourceUse class + # AllResourceTotal class class AllResourceTotal include BuildingSync::Helper include BuildingSync::XmlGetSet + # @param base_xml [REXML::Element] + # @param ns [String] def initialize(base_xml, ns) @base_xml = base_xml @ns = ns diff --git a/lib/buildingsync/audit_date.rb b/lib/buildingsync/audit_date.rb new file mode 100644 index 00000000..ea49e7a9 --- /dev/null +++ b/lib/buildingsync/audit_date.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +# ******************************************************************************* +# OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC. +# BuildingSync(R), Copyright (c) 2015-2020, Alliance for Sustainable Energy, LLC. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# (1) Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# (2) Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# (3) Neither the name of the copyright holder nor the names of any contributors +# may be used to endorse or promote products derived from this software without +# specific prior written permission from the respective party. +# +# (4) Other than as required in clauses (1) and (2), distributions in any form +# of modifications or other derivative works may not use the "OpenStudio" +# trademark, "OS", "os", or any other confusingly similar designation without +# specific prior written permission from Alliance for Sustainable Energy, LLC. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE +# UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF +# THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ******************************************************************************* + +module BuildingSync + # AuditDate class + class AuditDate + include BuildingSync::Helper + include BuildingSync::XmlGetSet + # @param base_xml [REXML::Element] + # @param ns [String] + def initialize(base_xml, ns) + @base_xml = base_xml + @ns = ns + + help_element_class_type_check(base_xml, 'AuditDate') + end + end +end diff --git a/lib/buildingsync/contact.rb b/lib/buildingsync/contact.rb new file mode 100644 index 00000000..a2b8d4be --- /dev/null +++ b/lib/buildingsync/contact.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +# ******************************************************************************* +# OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC. +# BuildingSync(R), Copyright (c) 2015-2020, Alliance for Sustainable Energy, LLC. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# (1) Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# (2) Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# (3) Neither the name of the copyright holder nor the names of any contributors +# may be used to endorse or promote products derived from this software without +# specific prior written permission from the respective party. +# +# (4) Other than as required in clauses (1) and (2), distributions in any form +# of modifications or other derivative works may not use the "OpenStudio" +# trademark, "OS", "os", or any other confusingly similar designation without +# specific prior written permission from Alliance for Sustainable Energy, LLC. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE +# UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF +# THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ******************************************************************************* + +module BuildingSync + # Contact class + class Contact + include BuildingSync::Helper + include BuildingSync::XmlGetSet + # @param base_xml [REXML::Element] + # @param ns [String] + def initialize(base_xml, ns) + @base_xml = base_xml + @ns = ns + + help_element_class_type_check(base_xml, 'Contact') + end + end +end diff --git a/lib/buildingsync/generator.rb b/lib/buildingsync/generator.rb index 6cb0ad00..9bc8cf61 100644 --- a/lib/buildingsync/generator.rb +++ b/lib/buildingsync/generator.rb @@ -475,16 +475,44 @@ def get_first_building_section_element(doc) return section end + def get_first_report_element(doc) + report = doc.get_elements("/#{@ns}:BuildingSync/#{@ns}:Facilities/#{@ns}:Facility/#{@ns}:Reports/#{@ns}:Report").first + return report + end + def get_first_scenario_element(doc) scenario = doc.get_elements("/#{@ns}:BuildingSync/#{@ns}:Facilities/#{@ns}:Facility/#{@ns}:Reports/#{@ns}:Report/#{@ns}:Scenarios/#{@ns}:Scenario").first return scenario end + def get_first_utility_element(doc) + scenario = doc.get_elements("/#{@ns}:BuildingSync/#{@ns}:Facilities/#{@ns}:Facility/#{@ns}:Reports/#{@ns}:Report/#{@ns}:Utilities/#{@ns}:Utility").first + return scenario + end + def get_first_hvac_system_element(doc) scenario = doc.get_elements("/#{@ns}:BuildingSync/#{@ns}:Facilities/#{@ns}:Facility/#{@ns}:Systems/#{@ns}:HVACSystems/#{@ns}:HVACSystem").first return scenario end + def get_utility_from_file(xml_file_path) + doc = nil + File.open(xml_file_path, 'r') do |file| + doc = REXML::Document.new(file) + end + report = get_first_utility_element(doc) + return BuildingSync::Utility.new(report, @ns) + end + + def get_report_from_file(xml_file_path) + doc = nil + File.open(xml_file_path, 'r') do |file| + doc = REXML::Document.new(file) + end + report = get_first_report_element(doc) + return BuildingSync::Report.new(report, @ns) + end + def get_facility_from_file(xml_file_path) doc = nil File.open(xml_file_path, 'r') do |file| diff --git a/lib/buildingsync/helpers/xml_get_set.rb b/lib/buildingsync/helpers/xml_get_set.rb index c08deba5..c2cfe063 100644 --- a/lib/buildingsync/helpers/xml_get_set.rb +++ b/lib/buildingsync/helpers/xml_get_set.rb @@ -137,6 +137,15 @@ def xget_idrefs(element_name) return to_return end + def xget_plurals_text_value(element_name) + plurals = @base_xml.get_elements(".//#{@ns}:#{element_name}s/#{@ns}:#{element_name}") + to_return = [] + plurals.each do |p| + to_return << help_get_text_value(p) + end + return to_return + end + # Get the linked premises ids of the @base_xml element # @return [Hash] where keys are premise types and values are an array of ids # @example {'Building' => ['Building-1', 'Building-1'], 'Section' => ['Section-4']]} @@ -183,8 +192,14 @@ def xset_or_create(element_name, new_value, override = true) element.text = new_value end else - new_element = REXML::Element.new("#{@ns}:#{element_name}", @base_xml) - new_element.text = new_value + element = REXML::Element.new("#{@ns}:#{element_name}", @base_xml) + element.text = new_value + end + if element.text.nil? + raise StandardError, "Unable to set #{element_name} to nil" + end + if element.text.empty? + raise StandardError, "Unable to set #{element_name} to be empty" end return element end diff --git a/lib/buildingsync/makers/workflow_maker.rb b/lib/buildingsync/makers/workflow_maker.rb index 8605e40e..4d680aab 100644 --- a/lib/buildingsync/makers/workflow_maker.rb +++ b/lib/buildingsync/makers/workflow_maker.rb @@ -133,7 +133,7 @@ def get_workflow # get scenario elements # @return [Array] def get_scenarios - return @facility.scenarios + return @facility.report.scenarios end # generate the baseline model as osm model @@ -384,17 +384,17 @@ def write_osws(main_output_dir) # make sure paths exist super - if @facility.cb_modeled.nil? + if @facility.report.cb_modeled.nil? OpenStudio.logFree(OpenStudio::Error, 'BuildingSync.WorkflowMaker.write_osws', 'OSW cannot be written since no current building modeled scenario is defined. One can be added after file import using the add_cb_modeled method') raise StandardError, 'OSW cannot be written since no current building modeled scenario is defined. One can be added after file import using the add_cb_modeled method' end # Write a workflow for the current building modeled scenario - cb_modeled_success = write_osw(main_output_dir, @facility.cb_modeled) + cb_modeled_success = write_osw(main_output_dir, @facility.report.cb_modeled) number_successful = cb_modeled_success ? 1 : 0 # write an osw for each Package Of Measures scenario - @facility.poms.each do |scenario| + @facility.report.poms.each do |scenario| successful = write_osw(main_output_dir, scenario) if successful number_successful += 1 @@ -402,7 +402,7 @@ def write_osws(main_output_dir) end # Compare the total number of potential successes to the number of actual successes - really_successful = number_successful == @facility.poms.size + 1 + really_successful = number_successful == @facility.report.poms.size + 1 return really_successful end @@ -527,11 +527,11 @@ def cleanup_larger_files(osw_dir) # @return [Boolean] def gather_results(year_val = Date.today.year, baseline_only = false) # Gather results for the Current Building Modeled (Baseline) Scenario - @facility.cb_modeled.os_gather_results(year_val) + @facility.report.cb_modeled.os_gather_results(year_val) if !baseline_only # Gather results for the Package of Measures scenarios - @facility.poms.each do |scenario| + @facility.report.poms.each do |scenario| scenario.os_gather_results(year_val) end end diff --git a/lib/buildingsync/model_articulation/building.rb b/lib/buildingsync/model_articulation/building.rb index 74028966..f023b5d9 100644 --- a/lib/buildingsync/model_articulation/building.rb +++ b/lib/buildingsync/model_articulation/building.rb @@ -150,14 +150,8 @@ def set_width_and_length def check_occupancy_classification(site_occupancy_classification) # Set the OccupancyClassification text as that defined by the Site # ONLY if it is not already defined - if !site_occupancy_classification.nil? && !site_occupancy_classification.empty? - xset_or_create('OccupancyClassification', site_occupancy_classification, false) - end + xset_or_create('OccupancyClassification', site_occupancy_classification, false) - if xget_text('OccupancyClassification').nil? || xget_text('OccupancyClassification').empty? - OpenStudio.logFree(OpenStudio::Error, 'BuildingSync.Building.check_occupancy_classification', 'OccupancyClassification must be set at either the Site or Building') - raise StandardError, 'BuildingSync.Building.check_occupancy_classification: OccupancyClassification must be set at either the Site or Building' - end end # Set the @built_year based on YearOfConstruction / YearOfLastMajorRemodel @@ -197,7 +191,7 @@ def read_stories_above_and_below_grade if @num_stories_below_grade > 1.0 OpenStudio.logFree(OpenStudio::Error, 'BuildingSync.Building.read_stories_above_and_below_grade', "Number of stories below grade is larger than 1: #{@num_stories_below_grade}, currently only one basement story is supported.") - raise "Error : Number of stories below grade is larger than 1: #{@num_stories_below_grade}, currently only one basement story is supported." + raise StandardError, "Building ID: #{xget_id}. Number of stories below grade is > 1 (#{num_stories_below_grade}). Currently, only one story below grade is supported." end end diff --git a/lib/buildingsync/model_articulation/facility.rb b/lib/buildingsync/model_articulation/facility.rb index 58137c22..69c34042 100644 --- a/lib/buildingsync/model_articulation/facility.rb +++ b/lib/buildingsync/model_articulation/facility.rb @@ -38,6 +38,8 @@ # ******************************************************************************* require 'openstudio/extension/core/os_lib_geometry' +require 'buildingsync/report' +require 'buildingsync/contact' require 'buildingsync/helpers/helper' require 'buildingsync/helpers/xml_get_set' require 'buildingsync/helpers/Model.hvac' @@ -71,39 +73,18 @@ def initialize(base_xml, ns) @site_xml = nil @site = nil - @scenarios = [] + @report = nil + @measures = [] - @cb_modeled = nil - @cb_measured = [] - @poms = [] - @systems_map = {} - # @hvac_systems = [] - # @loads_systems = [] - # @lighting_systems = [] @contacts = [] + @systems_map = {} - @auditor_contact_id = nil - @audit_date_level_1 = nil - @audit_date_level_2 = nil - @audit_date_level_3 = nil - @contact_auditor_name = nil - @contact_owner_name = nil + # TODO: Go under Report @utility_name = nil @utility_meter_numbers = [] @metering_configuration = nil - @rate_schedules_xml = [] - @interval_reading_monthly = [] - @interval_reading_yearly = [] @spaces_excluded_from_gross_floor_area = nil - # parameter to read and write. - @energy_resource = nil - @benchmark_tool = nil - @building_eui = nil - @building_eui_benchmark = nil - @energy_cost = nil - @annual_fuel_use_native_units = nil - @load_system = nil @hvac_system = nil @@ -138,22 +119,11 @@ def read_xml else @report_xml = report_xml_temp.first end + # Create new Report + @report = BuildingSync::Report.new(@report_xml, @ns) - scenarios_xml_temp = @report_xml.get_elements("#{@ns}:Scenarios/#{@ns}:Scenario") measures_xml_temp = @base_xml.get_elements("#{@ns}:Measures/#{@ns}:Measure") - # Scenarios - create and checks - cb_modeled = [] - scenarios_xml_temp&.each do |scenario_xml| - if scenario_xml.is_a? REXML::Element - sc = BuildingSync::Scenario.new(scenario_xml, @ns) - @scenarios.push(sc) - cb_modeled << sc if sc.cb_modeled? - @cb_measured << sc if sc.cb_measured? - @poms << sc if sc.pom? - end - end - # Measures - create if !measures_xml_temp.nil? measures_xml_temp.each do |measure_xml| @@ -164,24 +134,7 @@ def read_xml OpenStudio.logFree(OpenStudio::Info, 'BuildingSync.Facility.read_xml', "Facility with ID: #{xget_id} has #{@measures.size} Measure Objects") end - # -- Issue warnings for undesirable situations - if @scenarios.empty? - OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.read_xml', 'No Scenario elements found') - end - - # -- Logging for Scenarios - if cb_modeled.empty? - OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.read_xml', 'A Current Building Modeled Scenario is required.') - elsif cb_modeled.size > 1 - @cb_modeled = cb_modeled[0] - OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.read_xml', "Only 1 Current Building Modeled Scenario is supported. Using Scenario with ID: #{@cb_modeled.xget_id}") - else - @cb_modeled = cb_modeled[0] - OpenStudio.logFree(OpenStudio::Info, 'BuildingSync.Facility.read_xml', "Current Building Modeled Scenario has ID: #{@cb_modeled.xget_id}") - end - read_other_details - read_interval_reading read_and_create_initial_systems end @@ -208,7 +161,7 @@ def generate_baseline_osm(epw_file_path, output_path, standard_to_be_used, ddy_f @epw_file_path = @site.get_epw_file_path zone_hash = build_zone_hash(@site) - create_building_systems(output_path, zone_hash) + create_building_systems(output_path: output_path, zone_hash: zone_hash, remove_objects: true) return true end @@ -237,9 +190,22 @@ def get_epw_file_path @site.get_epw_file_path end - def get_measure_given_id(measure_id) - @measures.each do |measure| + # Get the ContactName specified by the AuditorContactID/@IDref + # @return [String] if exists + # @return [nil] if not + def get_auditor_contact_name + auditor_id = @report.get_auditor_contact_id + if !auditor_id.nil? + contact = @contacts.find { |contact| contact.xget_id == auditor_id} + return contact.xget_text('ContactName') end + return nil + end + + # get OpenStudio model + # @return [OpenStudio::Model] + def get_model + return @site.get_model end # determine OpenStudio system standard @@ -248,36 +214,6 @@ def determine_open_studio_system_standard return @site.determine_open_studio_system_standard end - # read interval reading - def read_interval_reading - interval_frequency = '' - reading_type = '' - interval_reading = '' - if @base_xml.elements["#{@ns}:Reports/#{@ns}:Report/#{@ns}:Scenarios/#{@ns}:Scenario/#{@ns}:ResourceUses/#{@ns}:ResourceUse/#{@ns}:EnergyResource"] - @energy_resource = @base_xml.elements["#{@ns}:Reports/#{@ns}:Report/#{@ns}:Scenarios/#{@ns}:Scenario/#{@ns}:ResourceUses/#{@ns}:ResourceUse/#{@ns}:EnergyResource"].text - else - @energy_resource = nil - end - - if @base_xml.elements["#{@ns}:Reports/#{@ns}:Report/#{@ns}:Scenarios/#{@ns}:Scenario/#{@ns}:TimeSeriesData/#{@ns}:TimeSeriesType/#{@ns}:IntervalFrequency"] - interval_frequency = @base_xml.elements["#{@ns}:Reports/#{@ns}:Report/#{@ns}:Scenarios/#{@ns}:Scenario/#{@ns}:TimeSeriesData/#{@ns}:TimeSeriesType/#{@ns}:IntervalFrequency"].text - end - - if @base_xml.elements["#{@ns}:Reports/#{@ns}:Report/#{@ns}:Scenarios/#{@ns}:Scenario/#{@ns}:TimeSeriesData/#{@ns}:TimeSeriesType/#{@ns}:ReadingType"] - reading_type = @base_xml.elements["#{@ns}:Reports/#{@ns}:Report/#{@ns}:Scenarios/#{@ns}:Scenario/#{@ns}:TimeSeriesData/#{@ns}:TimeSeriesType/#{@ns}:ReadingType"].text - end - - if @base_xml.elements["#{@ns}:Reports/#{@ns}:Report/#{@ns}:Scenarios/#{@ns}:Scenario/#{@ns}:TimeSeriesData/#{@ns}:TimeSeriesType/#{@ns}:IntervalReading"] - interval_reading = @base_xml.elements["#{@ns}:Reports/#{@ns}:Report/#{@ns}:Scenarios/#{@ns}:Scenario/#{@ns}:TimeSeriesData/#{@ns}:TimeSeriesType/#{@ns}:IntervalReading"].text - end - - if interval_frequency == 'Month' - @interval_reading_monthly.push(MeteredEnergy.new(@energy_resource, interval_frequency, reading_type, interval_reading)) - elsif interval_frequency == 'Year' - @interval_reading_yearly.push(MeteredEnergy.new(@energy_resource, interval_frequency, reading_type, interval_reading)) - end - end - # read systems def read_and_create_initial_systems systems_xml = xget_or_create('Systems') @@ -301,20 +237,9 @@ def read_and_create_initial_systems end end - # add a current building modeled scenario and set the @cb_modeled attribute - # @param id [String] id to use for the scenario - # @return [NilClass] + # @see BuildingSync::Report.add_cb_modeled def add_cb_modeled(id = "Scenario-#{BuildingSync::BASELINE}") - if @cb_modeled.nil? || @cb_modeled.empty? - g = BuildingSync::Generator.new - scenario_xml = g.add_scenario_to_report(@report_xml, 'CBModeled', id) - scenario = BuildingSync::Scenario.new(scenario_xml, @ns) - @scenarios.push(scenario) - @cb_modeled = scenario - OpenStudio.logFree(OpenStudio::Info, 'BuildingSync.WorkflowMaker.add_cb_modeled', "A Current Building Modeled scenario was added (Scenario ID: #{@cb_modeled.xget_id}).") - else - OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.WorkflowMaker.add_cb_modeled', "A Current Building Modeled scenario already exists (Scenario ID: #{@cb_modeled.xget_id}). A new one was not added.") - end + @report.add_cb_modeled(id) end # Add a minimal lighting system in the doc and as an object @@ -346,68 +271,7 @@ def add_blank_lighting_system(premise_id, premise_type, lighting_system_id = 'Li def read_other_details # Get Contact information @base_xml.elements.each("#{@ns}:Contacts/#{@ns}:Contact") do |contact| - contact.elements.each("#{@ns}:ContactRoles/#{@ns}:ContactRole") do |role| - if role.text == 'Energy Auditor' - @contact_auditor_name = contact.elements["#{@ns}:ContactName"].text - elsif role.text == 'Owner' - @contact_owner_name = contact.elements["#{@ns}:ContactName"].text - end - end - end - auditor_contact_id_element = @report_xml.elements["#{@ns}:AuditorContactID"] - - # Audit Level - audit_level = @report_xml.elements["#{@ns}:ASHRAEAuditLevel"] - if !audit_level.nil? - @audit_level = help_get_text_value(audit_level) - end - if !auditor_contact_id_element.nil? - @auditor_contact_id = help_get_attribute_value(auditor_contact_id_element, 'IDref') - end - - # Audit dates - audit_dates = @report_xml.get_elements("#{@ns}:AuditDates/#{@ns}:AuditDate") - if !audit_dates.nil? && !@audit_level.nil? - audit_dates.each do |audit_date| - if @audit_level == 'Level 1: Walk-through' - @audit_date_level_1 = help_get_text_value_as_date(audit_date.elements["#{@ns}:Date"]) - @audit_date = @audit_date_level_1 - elsif @audit_level == 'Level 2: Energy Survey and Analysis' - @audit_date_level_2 = help_get_text_value_as_date(audit_date.elements["#{@ns}:Date"]) - @audit_date = @audit_date_level_2 - elsif @audit_level == 'Level 3: Detailed Survey and Analysis' - @audit_date_level_3 = help_get_text_value_as_date(audit_date.elements["#{@ns}:Date"]) - @audit_date = @audit_date_level_3 - end - end - end - - # Read Utility Information - utilities = @report_xml.elements["#{@ns}:Utilities"] - utilities&.elements&.each("#{@ns}:Utility") do |utility| - @utility_name = help_get_text_value(utility.elements["#{@ns}:UtilityName"]) - @metering_configuration = help_get_text_value(utility.elements["#{@ns}:MeteringConfiguration"]) - meter_numbers = utility.get_elements("#{@ns}:UtilityMeterNumbers/#{@ns}:UtilityMeterNumber") - rate_schedules = utility.get_elements("#{@ns}:RateSchedules/#{@ns}:RateSchedule") - meter_numbers&.each do |mn| - @utility_meter_numbers << help_get_text_value(mn) - end - rate_schedules&.each do |rs| - @rate_schedules_xml << rs - end - end - - # Read UDFs - @report_xml.elements.each("#{@ns}:UserDefinedFields/#{@ns}:UserDefinedField") do |user_defined_field| - if user_defined_field.elements["#{@ns}:FieldName"].text == 'Audit Notes' - @audit_notes = user_defined_field.elements["#{@ns}:FieldValue"].text - elsif user_defined_field.elements["#{@ns}:FieldName"].text == 'Audit Team Notes' - @audit_team_notes = user_defined_field.elements["#{@ns}:FieldValue"].text - elsif user_defined_field.elements["#{@ns}:FieldName"].text == 'Auditor Years Of Experience' - @auditor_years_experience = user_defined_field.elements["#{@ns}:FieldValue"].text - elsif user_defined_field.elements["#{@ns}:FieldName"].text == 'Spaces Excluded From Gross Floor Area' - @spaces_excluded_from_gross_floor_area = user_defined_field.elements["#{@ns}:FieldValue"].text - end + @contacts << BuildingSync::Contact.new(contact, @ns) end end @@ -426,9 +290,9 @@ def read_other_details # @param add_hvac [Boolean] # @param add_thermostat [Boolean] # @param remove_objects [Boolean] - def create_building_systems(output_path, zone_hash = nil, hvac_delivery_type = 'Forced Air', htg_src = 'NaturalGas', clg_src = 'Electricity', - add_space_type_loads = true, add_constructions = true, add_elevators = false, add_exterior_lights = false, - add_exhaust = true, add_swh = true, add_hvac = true, add_thermostat = true, remove_objects = false) + def create_building_systems(output_path:, zone_hash: nil, hvac_delivery_type: 'Forced Air', htg_src: 'NaturalGas', clg_src: 'Electricity', + add_space_type_loads: true, add_constructions: true, add_elevators: false, add_exterior_lights: false, + add_exhaust: true, add_swh: true, add_hvac: true, add_thermostat: true, remove_objects: false) model = @site.get_model template = @site.get_standard_template system_type = @site.get_system_type @@ -494,7 +358,14 @@ def create_building_systems(output_path, zone_hash = nil, hvac_delivery_type = ' # add exterior lights (returns a hash where key is lighting type and value is exteriorLights object) if add_exterior_lights - @load_system.add_exterior_lights(model, open_studio_system_standard, onsite_parking_fraction, exterior_lighting_zone, remove_objects) + if !@systems_map['LightingSystems'].nil? + @systems_map['LightingSystems'].each do |lighting_system| + lighting_system.add_exterior_lights(model, open_studio_system_standard, onsite_parking_fraction, exterior_lighting_zone, remove_objects) + end + else + new_lighting_system = add_blank_lighting_system(@site.get_building.xget_id, 'Building') + new_lighting_system.add_exterior_lights(model, open_studio_system_standard, onsite_parking_fraction, exterior_lighting_zone, remove_objects) + end end # add_exhaust @@ -532,6 +403,11 @@ def create_building_systems(output_path, zone_hash = nil, hvac_delivery_type = ' # set hvac controls and efficiencies (this should be last model articulation element) if add_hvac + if remove_objects + model.purgeUnusedResourceObjects + objects_after_cleanup = initial_objects - model.getModelObjects.size + OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.create_building_system', "Removing #{objects_after_cleanup} objects from model") + end @hvac_system.apply_sizing_and_assumptions(model, output_path, open_studio_system_standard, primary_bldg_type, system_type, climate_zone) end @@ -557,27 +433,12 @@ def write_osm(dir) return scenario_types end + # TODO: I don't think we want any of this. # write parameters to xml def prepare_final_xml - report = @base_xml.elements["#{@ns}:Reports/#{@ns}:Report"] - report.elements.each("#{@ns}:Scenarios/#{@ns}:Scenario") do |scenario| - scenario.elements["#{@ns}:ResourceUses/#{@ns}:ResourceUse/#{@ns}:EnergyResource"].text = @energy_resource if !@energy_resource.nil? - scenario.elements["#{@ns}:ScenarioType/#{@ns}:Benchmark/#{@ns}:BenchmarkType/#{@ns}:Other"].text = @benchmark_tool if !@benchmark_tool.nil? - scenario.elements["#{@ns}:AllResourceTotals/#{@ns}:AllResourceTotal/#{@ns}:SiteEnergyUseIntensity"].text = @building_eui if !@building_eui.nil? - scenario.elements["#{@ns}:AllResourceTotals/#{@ns}:AllResourceTotal/#{@ns}:SiteEnergyUseIntensity"].text = @building_eui_benchmark if !@building_eui_benchmark.nil? - scenario.elements["#{@ns}:AllResourceTotals/#{@ns}:AllResourceTotal/#{@ns}:EnergyCost"].text = @energy_cost if !@energy_cost.nil? - scenario.elements["#{@ns}:ResourceUses/#{@ns}:ResourceUse/#{@ns}:AnnualFuelUseNativeUnits"].text = @annual_fuel_use_native_units if !@annual_fuel_use_native_units.nil? - end @site.prepare_final_xml end - # get OpenStudio model - # @return [OpenStudio::Model] - def get_model - return @site.get_model - end - - attr_reader :systems_map, :building_eui_benchmark, :building_eui, :auditor_contact_id, :annual_fuel_use_native_units, :audit_date, :benchmark_tool, :contact_auditor_name, :energy_cost, :energy_resource, - :rate_schedules_xml, :utility_meter_numbers, :utility_name, :metering_configuration, :scenarios, :poms, :cb_modeled, :cb_measured, :measures + attr_reader :systems_map, :site, :report, :measures, :contacts end end diff --git a/lib/buildingsync/model_articulation/site.rb b/lib/buildingsync/model_articulation/site.rb index d5acbbca..a3ebfbfe 100644 --- a/lib/buildingsync/model_articulation/site.rb +++ b/lib/buildingsync/model_articulation/site.rb @@ -47,6 +47,7 @@ def initialize(base_xml, ns) super(base_xml, ns) @base_xml = base_xml @ns = ns + help_element_class_type_check(base_xml, 'Site') @building = nil @all_set = false diff --git a/lib/buildingsync/report.rb b/lib/buildingsync/report.rb new file mode 100644 index 00000000..b8000771 --- /dev/null +++ b/lib/buildingsync/report.rb @@ -0,0 +1,217 @@ +# frozen_string_literal: true + +# ******************************************************************************* +# OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC. +# BuildingSync(R), Copyright (c) 2015-2020, Alliance for Sustainable Energy, LLC. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# (1) Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# (2) Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# (3) Neither the name of the copyright holder nor the names of any contributors +# may be used to endorse or promote products derived from this software without +# specific prior written permission from the respective party. +# +# (4) Other than as required in clauses (1) and (2), distributions in any form +# of modifications or other derivative works may not use the "OpenStudio" +# trademark, "OS", "os", or any other confusingly similar designation without +# specific prior written permission from Alliance for Sustainable Energy, LLC. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE +# UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF +# THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ******************************************************************************* + +require 'buildingsync/audit_date' +require 'buildingsync/scenario' +require 'buildingsync/utility' + +module BuildingSync + # Report class + class Report + include BuildingSync::Helper + include BuildingSync::XmlGetSet + # @param base_xml [REXML::Element] + # @param ns [String] + def initialize(base_xml, ns) + @base_xml = base_xml + @ns = ns + help_element_class_type_check(base_xml, 'Report') + + @scenarios = [] + @audit_dates = [] + @utilities = [] + + # Special scenarios + @cb_modeled = nil + @cb_measured = [] + @poms = [] + + read_xml + end + + def read_xml + read_scenarios + + # Audit dates + @base_xml.elements.each("#{@ns}:AuditDates/#{@ns}:AuditDate") do |audit_date| + @audit_dates << BuildingSync::AuditDate.new(audit_date, @ns) + end + + # Utilities + @base_xml.elements.each("#{@ns}:Utilities/#{@ns}:Utility") do |utility| + @utilities << BuildingSync::Utility.new(utility, @ns) + end + end + + def read_scenarios + # Scenarios - create and checks + scenarios_xml_temp = @base_xml.get_elements("#{@ns}:Scenarios/#{@ns}:Scenario") + cb_modeled = [] + scenarios_xml_temp&.each do |scenario_xml| + if scenario_xml.is_a? REXML::Element + sc = BuildingSync::Scenario.new(scenario_xml, @ns) + @scenarios.push(sc) + cb_modeled << sc if sc.cb_modeled? + @cb_measured << sc if sc.cb_measured? + @poms << sc if sc.pom? + end + end + + # -- Issue warnings for undesirable situations + if @scenarios.empty? + OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.read_xml', 'No Scenario elements found') + end + + # -- Logging for Scenarios + if cb_modeled.empty? + OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.read_xml', 'A Current Building Modeled Scenario is required.') + elsif cb_modeled.size > 1 + @cb_modeled = cb_modeled[0] + OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.read_xml', "Only 1 Current Building Modeled Scenario is supported. Using Scenario with ID: #{@cb_modeled.xget_id}") + else + @cb_modeled = cb_modeled[0] + OpenStudio.logFree(OpenStudio::Info, 'BuildingSync.Facility.read_xml', "Current Building Modeled Scenario has ID: #{@cb_modeled.xget_id}") + end + end + + def get_all_utility_meter_numbers + all = [] + @utilities.each do |utility| + all += utility.get_utility_meter_numbers + end + return all + end + + def get_all_utility_names + all = [] + @utilities.each do |utility| + all += utility.get_utility_meter_numbers + end + return all + end + + def get_auditor_contact_id + return xget_attribute_for_element('AuditorContactID', 'IDref') + end + + def get_newest_audit_date + dates = [] + @audit_dates.each do |date| + dates << date.xget_text_as_date('Date') + end + return dates.max + end + + def get_oldest_audit_date + dates = [] + @audit_dates.each do |date| + dates << date.xget_text_as_date('Date') + end + return dates.min + end + + # Get the SiteEnergyUseIntensity for the benchmark scenario. + # Where multiple benchmark scenarios exist, the value from the first is returned + # @see get_scenario_site_eui + def get_first_benchmark_site_eui + eui = [] + ids = [] + @scenarios.each do |scenario| + if scenario.benchmark? + eui << get_first_scenario_site_eui(scenario) + ids << scenario.xget_id + end + end + if eui.size == 1 + return eui[0] + elsif eui.size == 0 + OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.get_benchmark_site_eui', "No Benchmark Scenarios exist with SiteEnergyUseIntensity defined") + return nil + elsif eui.size > 1 + OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.get_benchmark_site_eui', "Multiple Benchmark Scenarios exist with SiteEnergyUseIntensity defined. Returning the value for Scenario ID: #{ids[0]}") + return eui[0] + end + end + + # Get the SiteEnergyUseIntensity for the cb_modeled scenario. + # @see get_scenario_site_eui + def get_first_cb_modeled_site_eui + return get_first_scenario_site_eui(@cb_modeled) + end + + # Get the AllResourceTotal/SiteEnergyUseIntensity value as a float. + # Where multiple AllResourceTotals exist with the value defined, the first is returned. + # @param scenario [BuildingSync::Scenario] the scenario + # @return [Float] if atleast one value is found + # @return [nil] if no value is found + def get_first_scenario_site_eui(scenario) + eui = [] + scenario.get_all_resource_totals.each do |art| + eui << art.xget_text_as_float('SiteEnergyUseIntensity') + end + if eui.size == 1 + return eui[0] + elsif eui.size == 0 + OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.get_scenario_site_eui', "Scenario ID: #{@cb_modeled.xget_id} does not have a SiteEnergyUseIntensity defined in any of the AllResourceTotal elements.") + return nil + elsif eui.size > 1 + OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.get_scenario_site_eui', "Scenario ID: #{@cb_modeled.xget_id} has more thant 1 (#{eui.size}) SiteEnergyUseIntensity defined in the AllResourceTotal elements. Returning the first.") + return eui[0] + end + end + + # add a current building modeled scenario and set the @cb_modeled attribute + # @param id [String] id to use for the scenario + # @return [NilClass] + def add_cb_modeled(id = "Scenario-#{BuildingSync::BASELINE}") + if @cb_modeled.nil? || @cb_modeled.empty? + g = BuildingSync::Generator.new + scenario_xml = g.add_scenario_to_report(@base_xml, 'CBModeled', id) + scenario = BuildingSync::Scenario.new(scenario_xml, @ns) + @scenarios.push(scenario) + @cb_modeled = scenario + OpenStudio.logFree(OpenStudio::Info, 'BuildingSync.WorkflowMaker.add_cb_modeled', "A Current Building Modeled scenario was added (Scenario ID: #{@cb_modeled.xget_id}).") + else + OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.WorkflowMaker.add_cb_modeled', "A Current Building Modeled scenario already exists (Scenario ID: #{@cb_modeled.xget_id}). A new one was not added.") + end + end + + attr_reader :scenarios, :cb_modeled, :cb_measured, :poms + end +end diff --git a/lib/buildingsync/scenario.rb b/lib/buildingsync/scenario.rb index 2916adca..cbfe14ea 100644 --- a/lib/buildingsync/scenario.rb +++ b/lib/buildingsync/scenario.rb @@ -215,6 +215,11 @@ def get_osw_dir return @osw_dir end + def get_benchmark_tool + child = get_scenario_type_child_element + return help_get_text_value(child.elements["#{@ns}:BenchmarkTool"]) + end + # @param workflow [Hash] a hash of the openstudio workflow def set_workflow(workflow) if !workflow.is_a?(Hash) diff --git a/lib/buildingsync/translator.rb b/lib/buildingsync/translator.rb index 51fba569..05dbb0e0 100644 --- a/lib/buildingsync/translator.rb +++ b/lib/buildingsync/translator.rb @@ -235,6 +235,7 @@ def run_baseline_osm(path_to_epw_file = nil, runner_options = { run_simulations: end file_name = 'in.osm' + # Create a new baseline directory: dir/@output_dir/Baseline osm_baseline_dir = File.join(@output_dir, BASELINE) if !File.exist?(osm_baseline_dir) diff --git a/lib/buildingsync/utility.rb b/lib/buildingsync/utility.rb new file mode 100644 index 00000000..8616a19c --- /dev/null +++ b/lib/buildingsync/utility.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +# ******************************************************************************* +# OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC. +# BuildingSync(R), Copyright (c) 2015-2020, Alliance for Sustainable Energy, LLC. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# (1) Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# (2) Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# (3) Neither the name of the copyright holder nor the names of any contributors +# may be used to endorse or promote products derived from this software without +# specific prior written permission from the respective party. +# +# (4) Other than as required in clauses (1) and (2), distributions in any form +# of modifications or other derivative works may not use the "OpenStudio" +# trademark, "OS", "os", or any other confusingly similar designation without +# specific prior written permission from Alliance for Sustainable Energy, LLC. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE +# UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF +# THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ******************************************************************************* + +module BuildingSync + # Utility class + class Utility + include BuildingSync::Helper + include BuildingSync::XmlGetSet + # @param base_xml [REXML::Element] + # @param ns [String] + def initialize(base_xml, ns) + @base_xml = base_xml + @ns = ns + help_element_class_type_check(base_xml, 'Utility') + + @rate_schedules = [] + end + + # @return [Array] + def get_utility_meter_numbers + return xget_plurals_text_value('UtilityMeterNumber') + end + end +end diff --git a/spec/tests/model_articulation_test/building_section_spec.rb b/spec/tests/model_articulation_test/building_section_spec.rb index 71efc02c..30a1e451 100644 --- a/spec/tests/model_articulation_test/building_section_spec.rb +++ b/spec/tests/model_articulation_test/building_section_spec.rb @@ -48,7 +48,6 @@ g.add_section_to_first_building(doc) @facility_xml = g.get_first_facility_element(doc) @section_xml = g.get_first_building_section_element(doc) - puts @section_xml end it 'should raise an error given a non-Section REXML Element' do BuildingSync::BuildingSection.new(@facility_xml, nil, nil, nil, @ns) @@ -62,9 +61,7 @@ # Should not reach this line expect(false).to be true rescue StandardError => e - puts e.message.to_s - puts "expected error message:Building type '' is nil but got: #{e.message} " if !e.message.include?("Building type '' is nil") - expect(e.message.include?("Building type '' is nil")).to be true + expect(e.message.to_s).to eq("Unable to set OccupancyClassification to nil") end end end diff --git a/spec/tests/model_articulation_test/building_spec.rb b/spec/tests/model_articulation_test/building_spec.rb index 4154eb2d..9009a60d 100644 --- a/spec/tests/model_articulation_test/building_spec.rb +++ b/spec/tests/model_articulation_test/building_spec.rb @@ -39,57 +39,104 @@ require 'buildingsync/model_articulation/building' RSpec.describe 'BuildingSpec' do - it 'should raise an StandardError given a non-Building REXML Element' do - # -- Setup - ns = 'auc' - v = '2.2.0' - g = BuildingSync::Generator.new(ns, v) - doc_string = g.create_bsync_root_to_building - doc = REXML::Document.new(doc_string) - facility_element = doc.elements["//#{ns}:Facility"] - - # -- Create Building object from Facility - begin - BuildingSync::Building.new(facility_element, '', '', ns) - - # Should not reach this - expect(false).to be true - rescue StandardError => e - puts e.message - expect(e.message).to eql 'Attempted to initialize Building object with Element name of: Facility' + describe 'Expected Errors' do + + it 'should raise an StandardError given a non-Building REXML Element' do + # -- Setup + ns = 'auc' + v = '2.2.0' + g = BuildingSync::Generator.new(ns, v) + doc_string = g.create_bsync_root_to_building + doc = REXML::Document.new(doc_string) + facility_element = doc.elements["//#{ns}:Facility"] + + # -- Create Building object from Facility + begin + BuildingSync::Building.new(facility_element, '', '', ns) + + # Should not reach this + expect(false).to be true + rescue StandardError => e + puts e.message + expect(e.message).to eql 'Attempted to initialize Building object with Element name of: Facility' + end end - end - it 'Should raise StandardError when OccupancyClassification not provided at the Site or Building level' do - # -- Setup - g = BuildingSync::Generator.new - doc_string = g.create_bsync_root_to_building - doc = REXML::Document.new(doc_string) - building_xml = g.get_first_building_element(doc) + it 'Should raise StandardError when YearOfConstruction not provided at the Building level' do + # -- Setup + g = BuildingSync::Generator.new + doc_string = g.create_bsync_root_to_building + doc = REXML::Document.new(doc_string) + building_xml = g.get_first_building_element(doc) - begin - b = BuildingSync::Building.new(building_xml, '', '', 'auc') + begin + b = BuildingSync::Building.new(building_xml, 'Retail', '', 'auc') - # Should not reach this line - expect(false).to be true - rescue StandardError => e - expect(e.message.to_s).to eq('BuildingSync.Building.check_occupancy_classification: OccupancyClassification must be set at either the Site or Building') + # Should not reach this line + expect(false).to be true + rescue StandardError => e + expect(e.message.to_s).to eq('Building ID: Building1. Year of Construction is blank in your BuildingSync file, but is required.') + end end - end + it 'Should raise StandardError when Site OccupancyClassification provided is empty string' do + # -- Setup + g = BuildingSync::Generator.new + doc_string = g.create_bsync_root_to_building + doc = REXML::Document.new(doc_string) + building_xml = g.get_first_building_element(doc) + # -- Setup - add necessary data + year_of_construction = help_get_or_create(building_xml, 'auc:YearOfConstruction') + year_of_construction.text = 1990 - it 'Should raise StandardError when YearOfConstruction not provided at the Building level' do - # -- Setup - g = BuildingSync::Generator.new - doc_string = g.create_bsync_root_to_building - doc = REXML::Document.new(doc_string) - building_xml = g.get_first_building_element(doc) + begin + b = BuildingSync::Building.new(building_xml, '', '', 'auc') - begin - b = BuildingSync::Building.new(building_xml, 'Retail', '', 'auc') + # Should not reach this line + expect(false).to be true + rescue StandardError => e + expect(e.message.to_s).to eq('Unable to set OccupancyClassification to be empty') + end + end + it 'Should raise StandardError when Site OccupancyClassification provided is nil' do + # -- Setup + g = BuildingSync::Generator.new + doc_string = g.create_bsync_root_to_building + doc = REXML::Document.new(doc_string) + building_xml = g.get_first_building_element(doc) + # -- Setup - add necessary data + year_of_construction = help_get_or_create(building_xml, 'auc:YearOfConstruction') + year_of_construction.text = 1990 + + begin + b = BuildingSync::Building.new(building_xml, nil, '', 'auc') + + # Should not reach this line + expect(false).to be true + rescue StandardError => e + expect(e.message.to_s).to eq('Unable to set OccupancyClassification to nil') + end + end + + it 'Should raise StandardError when FloorsBelowGrade or ConditionedFloorsBelowGrade > 1' do + # -- Setup + g = BuildingSync::Generator.new + doc_string = g.create_bsync_root_to_building + doc = REXML::Document.new(doc_string) + building_xml = g.get_first_building_element(doc) - # Should not reach this line - expect(false).to be true - rescue StandardError => e - expect(e.message.to_s).to eq('Building ID: Building1. Year of Construction is blank in your BuildingSync file, but is required.') + # -- Setup - add necessary data + year_of_construction = help_get_or_create(building_xml, 'auc:YearOfConstruction') + year_of_construction.text = 1990 + floors_below_grade = help_get_or_create(building_xml, 'auc:FloorsBelowGrade') + floors_below_grade.text = 2 + + begin + b = BuildingSync::Building.new(building_xml, 'Retail', '', 'auc') + + # Should not reach this line + expect(false).to be true + rescue StandardError => e + expect(e.message.to_s).to eq("Building ID: Building1. Number of stories below grade is > 1 (2.0). Currently, only one story below grade is supported.") + end end end @@ -153,17 +200,17 @@ end expectations = [ - # [expected value, method used to access, element_name] - ['Property management company', 'xget_text', ['Ownership']], - ['Health care-Inpatient hospital', 'xget_text', ['OccupancyClassification']], - ['Contact1', 'xget_attribute_for_element', ['PrimaryContactID', 'IDref']], - [Date.new(2019, 1, 1), 'xget_text_as_date', ['RetrocommissioningDate']], - [true, 'xget_text_as_bool', ['BuildingAutomationSystem']], - [true, 'xget_text_as_bool', ['HistoricalLandmark']], - [2010, 'xget_text_as_integer', ['YearOfLastEnergyAudit']], - [2003, 'xget_text_as_integer', ['YearOfLastMajorRemodel']], - [2010, 'xget_text_as_integer', ['YearOfLastEnergyAudit']], - [60.0, 'xget_text_as_float', ['PercentOccupiedByOwner']] + # [expected value, method used to access, element_name] + ['Property management company', 'xget_text', ['Ownership']], + ['Retail', 'xget_text', ['OccupancyClassification']], + ['Contact1', 'xget_attribute_for_element', ['PrimaryContactID', 'IDref']], + [Date.new(2019, 1, 1), 'xget_text_as_date', ['RetrocommissioningDate']], + [true, 'xget_text_as_bool', ['BuildingAutomationSystem']], + [true, 'xget_text_as_bool', ['HistoricalLandmark']], + [2010, 'xget_text_as_integer', ['YearOfLastEnergyAudit']], + [2003, 'xget_text_as_integer', ['YearOfLastMajorRemodel']], + [2010, 'xget_text_as_integer', ['YearOfLastEnergyAudit']], + [60.0, 'xget_text_as_float', ['PercentOccupiedByOwner']] ] expectations.each do |e| diff --git a/spec/tests/model_articulation_test/facility_spec.rb b/spec/tests/model_articulation_test/facility_spec.rb index dc115127..7ee91e41 100644 --- a/spec/tests/model_articulation_test/facility_spec.rb +++ b/spec/tests/model_articulation_test/facility_spec.rb @@ -40,88 +40,95 @@ require 'buildingsync/generator' -# RSpec.describe 'FacilitySpec' do -# it 'Should generate meaningful error when passing empty XML data' do -# # -- Setup -# g = BuildingSync::Generator.new -# doc_string = g.create_bsync_root_to_building -# doc = REXML::Document.new(doc_string) -# facility_xml = g.get_first_facility_element(doc) -# begin -# f = BuildingSync::Facility.new(facility_xml, 'auc') -# -# # Should not reach this line -# expect(false).to be true -# rescue StandardError => e -# puts "expected error message:Year of Construction is blank in your BuildingSync file. but got: #{e.message} " if !e.message.include?('Year of Construction is blank in your BuildingSync file.') -# expect(e.message.include?('Year of Construction is blank in your BuildingSync file.')).to be true -# end -# end -# -# # TODO: Add actual assertions -# it 'Should create an instance of the facility class with minimal XML snippet' do -# generator = BuildingSync::Generator.new -# generator.create_minimum_facility('Retail', '1954', 'Gross', '69452') -# end -# -# it 'Should return the boolean value for creating osm file correctly or not.' do -# # -- Setup -# file_name = 'building_151.xml' -# std = ASHRAE90_1 -# xml_path, output_path = create_xml_path_and_output_path(file_name, std, __FILE__, 'v2.2.0') -# epw_path = File.join(SPEC_WEATHER_DIR, 'USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw') -# expect(File.exist?(epw_path)).to be true -# -# generator = BuildingSync::Generator.new -# facility = generator.create_minimum_facility('Retail', '1954', 'Gross', '69452') -# facility.determine_open_studio_standard(std) -# -# # -- Assert -# expect(facility.generate_baseline_osm(epw_path, output_path, std)).to be true -# end -# -# # TODO: Add actual assertions -# it 'Should create a building system with parameters set to true' do -# # -- Setup -# file_name = 'building_151.xml' -# std = ASHRAE90_1 -# xml_path, output_path = create_xml_path_and_output_path(file_name, std, __FILE__, 'v2.2.0') -# doc = nil -# File.open(xml_path, 'r') do |file| -# doc = REXML::Document.new(file) -# end -# ns = 'auc' -# -# # -- Act -# facility = BuildingSync::Facility.new(doc.elements["/#{ns}:BuildingSync/#{ns}:Facilities/#{ns}:Facility"], ns) -# facility.determine_open_studio_standard(ASHRAE90_1) -# facility.generate_baseline_osm(nil, output_path, ASHRAE90_1) -# facility.create_building_systems(output_path, nil, 'Forced Air', 'Electricity', 'Electricity', -# true, true, true, true, -# true, true, true, true, true) -# end -# -# # TODO: Add actual assertions -# it 'Should create a building system with parameters set to false' do -# # -- Setup -# file_name = 'building_151.xml' -# std = ASHRAE90_1 -# xml_path, output_path = create_xml_path_and_output_path(file_name, std, __FILE__, 'v2.2.0') -# doc = nil -# File.open(xml_path, 'r') do |file| -# doc = REXML::Document.new(file) -# end -# -# # -- Act -# ns = 'auc' -# facility = BuildingSync::Facility.new(doc.elements["/#{ns}:BuildingSync/#{ns}:Facilities/#{ns}:Facility"], ns) -# facility.determine_open_studio_standard(ASHRAE90_1) -# facility.generate_baseline_osm(nil, output_path, ASHRAE90_1) -# facility.create_building_systems(output_path, 'Forced Air', 'Electricity', 'Electricity', -# false, false, false, false, -# false, false, false, false, false) -# end -# end +RSpec.describe 'FacilitySpec' do + describe 'Expected Errors' do + + it 'should raise an StandardError given a non-Facility REXML Element' do + # -- Setup + ns = 'auc' + v = '2.2.0' + g = BuildingSync::Generator.new(ns, v) + doc_string = g.create_bsync_root_to_building + doc = REXML::Document.new(doc_string) + + # -- Create Building object from Facility + begin + BuildingSync::Facility.new(doc.root, ns) + + # Should not reach this + expect(false).to be true + rescue StandardError => e + puts e.message + expect(e.message).to eql 'Attempted to initialize Facility object with Element name of: BuildingSync' + end + end + end + + # TODO: Add actual assertions + it 'Should create an instance of the facility class with minimal XML snippet' do + generator = BuildingSync::Generator.new + generator.create_minimum_facility('Retail', '1954', 'Gross', '69452') + end + + it 'Should return the boolean value for creating osm file correctly or not.' do + # -- Setup + file_name = 'building_151.xml' + std = ASHRAE90_1 + xml_path, output_path = create_xml_path_and_output_path(file_name, std, __FILE__, 'v2.2.0') + epw_path = File.join(SPEC_WEATHER_DIR, 'USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw') + expect(File.exist?(epw_path)).to be true + + generator = BuildingSync::Generator.new + facility = generator.create_minimum_facility('Retail', '1954', 'Gross', '69452') + facility.determine_open_studio_standard(std) + + # -- Assert + expect(facility.generate_baseline_osm(epw_path, output_path, std)).to be true + end + + # TODO: Add actual assertions + it 'Should create a building system with parameters set to true' do + # -- Setup + file_name = 'building_151.xml' + std = ASHRAE90_1 + xml_path, output_path = create_xml_path_and_output_path(file_name, std, __FILE__, 'v2.2.0') + doc = nil + File.open(xml_path, 'r') do |file| + doc = REXML::Document.new(file) + end + ns = 'auc' + + # -- Act + facility = BuildingSync::Facility.new(doc.elements["/#{ns}:BuildingSync/#{ns}:Facilities/#{ns}:Facility"], ns) + facility.determine_open_studio_standard(ASHRAE90_1) + facility.generate_baseline_osm(nil, output_path, ASHRAE90_1) + facility.create_building_systems(output_path: output_path, htg_src: 'Electricity', + add_elevators: true, add_exterior_lights: true, remove_objects: true) + end + +# TODO: Add actual assertions + it 'Should create a building system with parameters set to false' do + # -- Setup + file_name = 'building_151.xml' + std = ASHRAE90_1 + xml_path, output_path = create_xml_path_and_output_path(file_name, std, __FILE__, 'v2.2.0') + doc = nil + File.open(xml_path, 'r') do |file| + doc = REXML::Document.new(file) + end + + # -- Act + ns = 'auc' + facility = BuildingSync::Facility.new(doc.elements["/#{ns}:BuildingSync/#{ns}:Facilities/#{ns}:Facility"], ns) + facility.determine_open_studio_standard(ASHRAE90_1) + facility.generate_baseline_osm(nil, output_path, ASHRAE90_1) + facility.create_building_systems(output_path: output_path, zone_hash: nil, hvac_delivery_type: 'Forced Air', + htg_src: 'Electricity', clg_src: 'Electricity', add_space_type_loads: false, + add_constructions: false, add_elevators: false, add_exterior_lights: false, + add_exhaust: false, add_swh: false, add_hvac: false, add_thermostat: false, + remove_objects: false) + end +end RSpec.describe 'Facility Scenario Parsing' do before(:each) do @@ -140,8 +147,8 @@ facility = BuildingSync::Generator.new.get_facility_from_file(xml_path) # -- Assert - expect(facility.scenarios.size).to eq 30 - facility.scenarios.each do |scenario| + expect(facility.report.scenarios.size).to eq 30 + facility.report.scenarios.each do |scenario| expect(scenario).to be_an_instance_of(BuildingSync::Scenario) end end @@ -155,8 +162,8 @@ facility = BuildingSync::Facility.new(@facility_xml, @ns) # -- Assert - expect(facility.scenarios).to be_an_instance_of(Array) - expect(facility.scenarios.empty?).to be true + expect(facility.report.scenarios).to be_an_instance_of(Array) + expect(facility.report.scenarios.empty?).to be true end end @@ -235,35 +242,13 @@ @facility = BuildingSync::Generator.new.get_facility_from_file(xml_path) end describe 'building_151_level1.xml' do - it 'Should return benchmark_eui' do - expected_value = '9.7' - - # -- Assert - expect(@facility.building_eui_benchmark == expected_value).to be true - end - - it 'Should return eui_building' do - # -- Setup - expected_value = '10.5' - - # -- Assert - expect(@facility.building_eui == expected_value).to be true - end - - it 'Should return auditor_contact_id' do - # -- Setup - expected_value = 'Contact1' - # -- Assert - expect(@facility.auditor_contact_id == expected_value).to be true - end - - it 'Should return benchmark_tool' do + it 'Should return contact_name' do # -- Setup - expected_value = 'Portfolio Manager' + expected_value = 'a contact person' # -- Assert - expect(@facility.benchmark_tool == expected_value).to be true + expect(@facility.get_auditor_contact_name).to eql(expected_value) end it 'Should return annual_fuel_use_native_units' do @@ -282,22 +267,6 @@ expect(@facility.energy_cost == expected_value).to be true end - it 'Should return audit_date' do - # -- Setup - expected_value = Date.parse('2019-05-01') - - # -- Assert - expect(@facility.audit_date == expected_value).to be true - end - - it 'Should return utility_name' do - # -- Setup - expected_value = 'an utility' - - # -- Assert - expect(@facility.utility_name == expected_value).to be true - end - it 'Should return metering_configuration ' do # -- Setup expected_value = 'Direct metering' @@ -316,47 +285,5 @@ expect(rate_structure_type.to_s == expected_value.to_s).to be true end - it 'Should return utility_meter_numbers' do - # -- Setup - expected_value = '0123456' - meter_number = @facility.utility_meter_numbers[0] - - # -- Assert - puts "expected utility_meter_number: #{expected_value} but got: #{meter_number} " if meter_number != expected_value - expect(meter_number == expected_value).to be true - end - end -end - -RSpec.describe 'Facility Methods' do - before(:all) do - # -- Setup - file_name = 'report_479.xml' - std = ASHRAE90_1 - @xml_path, output_path = create_xml_path_and_output_path(file_name, std, __FILE__) - - @facility = BuildingSync::Generator.new.get_facility_from_file(@xml_path) - end - describe 'report_479.xml' do - it 'Should return error about number of stories below grade' do - # -- Setup - - BuildingSync::Generator.new.get_facility_from_file(@xml_path) - - # Should not get here - expect(false).to be true - rescue StandardError => e - # -- Assert - puts "rescued StandardError: #{e.message}" - expect(e.message.include?('Number of stories below grade is larger than')).to be true - end - - it 'Should return contact_name' do - # -- Setup - expected_value = 'John Doe' - - # -- Assert - expect(@facility.contact_auditor_name == expected_value).to be true - end end -end +end \ No newline at end of file diff --git a/spec/tests/report_spec.rb b/spec/tests/report_spec.rb new file mode 100644 index 00000000..3c36bd38 --- /dev/null +++ b/spec/tests/report_spec.rb @@ -0,0 +1,103 @@ +# frozen_string_literal: true + +# ******************************************************************************* +# OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC. +# BuildingSync(R), Copyright (c) 2015-2020, Alliance for Sustainable Energy, LLC. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# (1) Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# (2) Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# (3) Neither the name of the copyright holder nor the names of any contributors +# may be used to endorse or promote products derived from this software without +# specific prior written permission from the respective party. +# +# (4) Other than as required in clauses (1) and (2), distributions in any form +# of modifications or other derivative works may not use the "OpenStudio" +# trademark, "OS", "os", or any other confusingly similar designation without +# specific prior written permission from Alliance for Sustainable Energy, LLC. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE +# UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF +# THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ******************************************************************************* +require 'buildingsync/report' + +RSpec.describe 'Report Spec' do + describe 'Methods' do + before(:all) do + # -- Setup + file_name = 'building_151_level1.xml' + std = ASHRAE90_1 + xml_path, output_path = create_xml_path_and_output_path(file_name, std, __FILE__, 'v2.2.0') + + @report = BuildingSync::Generator.new.get_report_from_file(xml_path) + end + # TODO: Is this the functionality we want? Or do we only want previous results + # to be deleted when we are populating new results? + it 'Should return nil for get_first_cb_modeled_site_eui since Current Building Modeled data gets wiped on Scenario Instantiation' do + # -- Setup + expected_value = nil + + # -- Assert + expect(@report.get_first_cb_modeled_site_eui).to eql(expected_value) + end + it 'Should return get_first_benchmark_site_eui since Benchmark data does not get wiped on Scenario Instantiation' do + expected_value = 9.7 + + # -- Assert + expect(@report.get_first_benchmark_site_eui).to eql(expected_value) + end + + it 'Should return auditor_contact_id' do + # -- Setup + expected_value = 'Contact1' + + # -- Assert + expect(@report.get_auditor_contact_id).to eql(expected_value) + end + + it 'Should return utility_meter_numbers' do + # -- Setup + expected_value = '0123456' + meter_numbers = @report.get_all_utility_meter_numbers + expect(meter_numbers.size).to eql 1 + + # -- Assert + expect(meter_numbers[0]).to eql(expected_value) + end + + it 'Should return BenchmarkTool value' do + # -- Setup + expected_value = 'Portfolio Manager' + benchmark = @report.scenarios.find { |scenario| scenario.benchmark? } + cb_modeled = @report.scenarios.find { |scenario| scenario.cb_modeled? } + + # -- Assert + expect(benchmark.get_benchmark_tool).to eql(expected_value) + expect(cb_modeled.get_benchmark_tool).to eql(nil) + end + + it 'Should return the most recent audit data' do + # -- Setup + expected_value = Date.parse('2019-05-01') + + expect(@report.get_newest_audit_date).to eql(expected_value) + end + end +end \ No newline at end of file diff --git a/spec/tests/utility_spec.rb b/spec/tests/utility_spec.rb new file mode 100644 index 00000000..a2e061cd --- /dev/null +++ b/spec/tests/utility_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +# ******************************************************************************* +# OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC. +# BuildingSync(R), Copyright (c) 2015-2020, Alliance for Sustainable Energy, LLC. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# (1) Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# (2) Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# (3) Neither the name of the copyright holder nor the names of any contributors +# may be used to endorse or promote products derived from this software without +# specific prior written permission from the respective party. +# +# (4) Other than as required in clauses (1) and (2), distributions in any form +# of modifications or other derivative works may not use the "OpenStudio" +# trademark, "OS", "os", or any other confusingly similar designation without +# specific prior written permission from Alliance for Sustainable Energy, LLC. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE +# UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF +# THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ******************************************************************************* +require 'buildingsync/utility' + +RSpec.describe 'Utility Spec' do + describe 'Methods' do + before(:all) do + # -- Setup + file_name = 'building_151_level1.xml' + std = ASHRAE90_1 + xml_path, output_path = create_xml_path_and_output_path(file_name, std, __FILE__, 'v2.2.0') + + @utility = BuildingSync::Generator.new.get_utility_from_file(xml_path) + end + + it 'Should return utility_name' do + # -- Setup + expected_value = 'an utility' + + # -- Assert + expect(@utility.xget_name).to eql(expected_value) + end + end +end diff --git a/spec/tests/workflow_maker_spec.rb b/spec/tests/workflow_maker_spec.rb index 921bedda..2cb6368c 100644 --- a/spec/tests/workflow_maker_spec.rb +++ b/spec/tests/workflow_maker_spec.rb @@ -287,7 +287,7 @@ # even though this is the cb_modeled scenario, because the main @workflow was directly # modified, and a deep copy of this is made in workflow_maker.write_osws.write_osw, # the measure will get run in the cb_modeled scenario. - expect(@workflow_maker.get_facility.cb_modeled.simulation_success?).to be true + expect(@workflow_maker.get_facility.report.cb_modeled.simulation_success?).to be true end end @@ -334,7 +334,7 @@ # even though this is the cb_modeled scenario, because the main @workflow was directly # modified, and a deep copy of this is made in workflow_maker.write_osws.write_osw, # the measure will get run in the cb_modeled scenario. - expect(@workflow_maker.get_facility.cb_modeled.simulation_success?).to be true + expect(@workflow_maker.get_facility.report.cb_modeled.simulation_success?).to be true end end