lib/openstudio-standards/standards/necb/ECMS/pv_ground.rb in openstudio-standards-0.2.14 vs lib/openstudio-standards/standards/necb/ECMS/pv_ground.rb in openstudio-standards-0.2.15.pre.rc1
- old
+ new
@@ -1,9 +1,7 @@
class ECMS
-
def apply_pv_ground(model:, pv_ground_type:, pv_ground_total_area_pv_panels_m2:, pv_ground_tilt_angle:, pv_ground_azimuth_angle:, pv_ground_module_description:)
-
##### Remove leading or trailing whitespace in case users add them in inputs
if pv_ground_total_area_pv_panels_m2.instance_of?(String)
pv_ground_total_area_pv_panels_m2 = pv_ground_total_area_pv_panels_m2.strip
end
if pv_ground_tilt_angle.instance_of?(String)
@@ -30,25 +28,12 @@
if pv_ground_azimuth_angle.instance_of?(String) && pv_ground_azimuth_angle != 'NECB_Default'
pv_ground_azimuth_angle = pv_ground_azimuth_angle.to_f
end
##### Calculate footprint of the building model (this is used as default value for pv_ground_total_area_pv_panels_m2)
- building_footprint_m2_array = []
- lowest_floor = 10000000000.0 #dummy number as initialization to find the lowest floor among spaces #TODO: Question:it it fine that it has been assumed that the floor of all lowest spaces are at the same level?
- model.getSpaces.sort.each do |space|
- space.surfaces.sort.select{ |surface| (surface.surfaceType == 'Floor') && (surface.outsideBoundaryCondition != 'Surface') && (surface.outsideBoundaryCondition != 'Adiabatic')}.each do |surface|
- floor_vertices = surface.vertices
- floor_z = floor_vertices[0].z.round(1)
- if floor_z <= lowest_floor
- lowest_floor = floor_z
- building_footprint_m2_array << surface.netArea
- end
- end
- end
- building_footprint_m2 = building_footprint_m2_array.sum
- puts "building_footprint_m2 is #{building_footprint_m2}"
-
+ building_footprint_m2 = calculate_building_footprint(model: model)
+ # puts "building_footprint_m2 is #{building_footprint_m2}"
##### Set default PV panels' total area as the building footprint
if pv_ground_total_area_pv_panels_m2 == 'NECB_Default'
pv_ground_total_area_pv_panels_m2 = building_footprint_m2
end
@@ -58,47 +43,63 @@
pv_ground_tilt_angle = epw.latitude.to_f
end
##### Set default PV panels' azimuth angle as south-facing arrays
if pv_ground_azimuth_angle == 'NECB_Default'
- pv_ground_azimuth_angle = 180 # EnergyPlus I/O Reference: "An azimuth angle of 180° is for a south-facing array, and an azimuth angle of 0° is for a north-facing array."
+ pv_ground_azimuth_angle = 180 # EnergyPlus I/O Reference: "An azimuth angle of 180deg is for a south-facing array, and an azimuth angle of 0deg is for a north-facing array."
end
##### Set default PV module type as the the below one
if pv_ground_module_description == 'NECB_Default'
pv_ground_module_description = 'HES-160-36PV 26.6 x 58.3 x 1.38' # Note: As per Mike Lubun's comment, assuming a typical panel is 5 ft x 2 ft, the closest standard type PV panel in the spreadsheet would be the 160W HES.
end
##### Calculate number of PV panels
# Note: assuming 5 ft x 2 ft as PV panel's size since it seems to fit the racking system used for ground mounts as per Mike Lubun's comment.
pv_area_each_ft2 = 5.0 * 2.0
- pv_area_each_m2 = (OpenStudio.convert(pv_area_each_ft2, 'ft^2', 'm^2').get) #convert pv_area_each_ft2 to m2
- pv_number_panels = pv_ground_total_area_pv_panels_m2/pv_area_each_m2
+ pv_area_each_m2 = OpenStudio.convert(pv_area_each_ft2, 'ft^2', 'm^2').get # convert pv_area_each_ft2 to m2
+ pv_number_panels = pv_ground_total_area_pv_panels_m2 / pv_area_each_m2
##### Get data of the PV panel from the json file
pv_info = @standards_data['tables']['pv']['table'].detect { |item| item['pv_module_description'] == pv_ground_module_description }
pv_ground_module_type = pv_info['pv_module_type']
pv_watt = pv_info['pv_module_wattage']
##### Create the generator
# Assuming one PVWatts generator in E+ as per Mike Lubun's comment for simplification, however exact number of PVWatts generators (and inverters) are calculated for costing.
dc_system_capacity = pv_number_panels * pv_watt
- generator = OpenStudio::Model::GeneratorPVWatts.new(model,dc_system_capacity)
+ generator = OpenStudio::Model::GeneratorPVWatts.new(model, dc_system_capacity)
generator.setModuleType(pv_ground_module_type)
- generator.setArrayType('OneAxis') # Note: "tilt and azimuth are fixed" for this array type (see E+ I/O Reference). This array type has been chosen as per Mike Lubun's costing spec.
+ generator.setArrayType('OneAxis') # Note: "tilt and azimuth are fixed" for this array type (see E+ I/O Reference). This array type has been chosen as per Mike Lubun's costing spec.
generator.setTiltAngle(pv_ground_tilt_angle)
generator.setAzimuthAngle(pv_ground_azimuth_angle)
##### Create the inverter
inverter = OpenStudio::Model::ElectricLoadCenterInverterPVWatts.new(model)
inverter.setDCToACSizeRatio(1.1) # Note: This is EnergyPlus' default value; This default value has been chosen for ground-mounted PV, assuming no storage as per Mike Lubun's costing spec.
inverter.setInverterEfficiency(0.96) # Note: This is EnergyPlus' default value; This default value has been chosen as per Mike Lubun's costing spec.
##### Get distribution systems and set relevant parameters
- model.getElectricLoadCenterDistributions.sort.each do |elc_distribution|
+ model.getElectricLoadCenterDistributions.sort.each do |elc_distribution|
elc_distribution.setInverter(inverter)
- elc_distribution.setGeneratorOperationSchemeType('Baseload') # E+ I/O Reference: "The Baseload scheme requests all generators scheduled ON (available) to operate, even if the amount of electric power generated exceeds the total facility electric power demand." This scheme type has been chosen as per Mike Lubun's costing spec.
+ elc_distribution.setGeneratorOperationSchemeType('Baseload') # E+ I/O Reference: "The Baseload scheme requests all generators scheduled ON (available) to operate, even if the amount of electric power generated exceeds the total facility electric power demand." This scheme type has been chosen as per Mike Lubun's costing spec.
end
-
end
+ # Method for calculating footprint of the building model
+ def calculate_building_footprint(model:)
+ building_footprint_m2_array = []
+ lowest_floor = 10000000000.0 # dummy number as initialization to find the lowest floor among spaces #TODO: Question:it it fine that it has been assumed that the floor of all lowest spaces are at the same level?
+ model.getSpaces.sort.each do |space|
+ space.surfaces.sort.select { |surface| (surface.surfaceType == 'Floor') && (surface.outsideBoundaryCondition != 'Surface') && (surface.outsideBoundaryCondition != 'Adiabatic') }.each do |surface|
+ floor_vertices = surface.vertices
+ floor_z = floor_vertices[0].z.round(1)
+ if floor_z <= lowest_floor
+ lowest_floor = floor_z
+ building_footprint_m2_array << surface.netArea
+ end
+ end
+ end
+ building_footprint_m2 = building_footprint_m2_array.sum
+ return building_footprint_m2
+ end
end