Question-and-Answer Resource for the Building Energy Modeling Community
Get started with the Help page
Ask Your Question

Revision history [back]

The original Window to Wall Ratio measure does just look at surface orientation along with surface type, but you can rally filter any way you want to. This could b based on surface, space, or space type name, or some other attribute of one of those objects.

When we made the AEDG measures we had added the plenum object to OpenStudio so those fenestration measures do skip plenums, but it figures out the plenum by a user specified standards space type (more reliable then just using the name of a space type). The office and school have different logic on the size of the window based on how the guides were written. This includes a customized version of what is north, south, east, west vs. the way our basic measure works (which splits at the 45 degrees).

AEDG Small to Medium Office - Fenestration and Daylighting Controls

AEDG K12 - Fenestration and Daylighting Controls

Below I pasted in a block of code from our basic measure. It loops through each surafces without regard to which space they come from, but it could very easily be changed to first loop through spaces or even space types, and then for each space it could loop through surfaces.

You could add any kind of logic to skip a space type such as what is below

next if not space_type.name.to_s.include? "plenum"

There is an OpenStudio option to check of a zone is a plenum, but that would only be useful after the HVAC system has been added, which typically would be after fenestration is created. Any sort of name or space type filter requires the user to take some action to identify spaces that they later intend to use as plenums. One alternate solution would be to keep the logic similar to what is in the main block below, but check each surface to see that it is higher than a target test height. This could be a hard coded height or could be a user argument. This would work without much prior thought from the modeler, other than what would be typical for a plenum.

 #data for final condition wwr
surfaces = model.getSurfaces
surfaces.each do |s|
  next if not s.surfaceType == "Wall"
  next if not s.outsideBoundaryCondition == "Outdoors"
  if s.space.empty?
    runner.registerWarning("#{s.name} doesn't have a parent space and won't be included in the measure reporting or modifications.")
    next
  end

  # get the absoluteAzimuth for the surface so we can categorize it
  absoluteAzimuth =  OpenStudio::convert(s.azimuth,"rad","deg").get + s.space.get.directionofRelativeNorth + model.getBuilding.northAxis
  until absoluteAzimuth < 360.0
    absoluteAzimuth = absoluteAzimuth - 360.0
  end

  if facade == "North"
    next if not (absoluteAzimuth >= 315.0 or absoluteAzimuth < 45.0)
  elsif facade == "East"
    next if not (absoluteAzimuth >= 45.0 and absoluteAzimuth < 135.0)
  elsif facade == "South"
    next if not (absoluteAzimuth >= 135.0 and absoluteAzimuth < 225.0)
  elsif facade == "West"
    next if not (absoluteAzimuth >= 225.0 and absoluteAzimuth < 315.0)
  else
    runner.registerError("Unexpected value of facade: " + facade + ".")
    return false
  end

  #get surface area adjusting for zone multiplier
  space = s.space
  if not space.empty?
    zone = space.get.thermalZone
  end
  if not zone.empty?
    zone_multiplier = zone.get.multiplier
    if zone_multiplier > 1
    end
  else
    zone_multiplier = 1 #space is not in a thermal zone
  end
  surface_gross_area = s.grossArea * zone_multiplier

  #loop through sub surfaces and add area including multiplier
  ext_window_area = 0
  s.subSurfaces.each do |subSurface| #onlky one and should have multiplier of 1
    ext_window_area = ext_window_area + subSurface.grossArea * subSurface.multiplier * zone_multiplier
  end

  final_gross_ext_wall_area += surface_gross_area
  final_ext_window_area += ext_window_area
end #end of surfaces.each do

Right after the line that checks to see if outsideBoundaryCondition == "Outdoors" you could add this code.

 zValueArray = []

 # get the existing vertices
 vertices = s.vertices
 vertices.each do |vertex|
   # push z value to array
   zValueArray << vertex.z
 end

 #skip if fails test
 test_height = 6 # feet
 next if zValueArray.max - zValueArray.min > OpenStudio::convert(test_height,"ft","m").get

The original Window to Wall Ratio measure does just look at surface orientation along with surface type, but you can rally really filter any way you want to. This could b be based on surface, space, building story, or space type name, or some other attribute of one of those objects.

When we made the AEDG measures we had added the plenum object to OpenStudio so those fenestration measures do skip plenums, but it figures out the plenum by a user specified standards space type (more reliable then just using the name of a space type). The office and school have different logic on the size of the window based on how the guides were written. This includes a customized version of what is north, south, east, west vs. the way our basic measure works (which splits at the 45 degrees).

AEDG Small to Medium Office - Fenestration and Daylighting Controls

AEDG K12 - Fenestration and Daylighting Controls

Below I pasted in a block of code from our basic measure. It loops through each surafces without regard to which space they come from, but it could very easily be changed to first loop through spaces or even space types, and then for each space it could loop through surfaces.

You could add any kind of logic to skip a space type such as what is below

next if not space_type.name.to_s.include? "plenum"

There is an OpenStudio option to check of a zone is a plenum, but that would only be useful after the HVAC system has been added, which typically would be after fenestration is created. Any sort of name or space type filter requires the user to take some action to identify spaces that they later intend to use as plenums. One alternate solution would be to keep the logic similar to what is in the main block below, but check each surface to see that it is higher than a target test height. This could be a hard coded height or could be a user argument. This would work without much prior thought from the modeler, other than what would be typical for a plenum.

 #data for final condition wwr
surfaces = model.getSurfaces
surfaces.each do |s|
  next if not s.surfaceType == "Wall"
  next if not s.outsideBoundaryCondition == "Outdoors"
  if s.space.empty?
    runner.registerWarning("#{s.name} doesn't have a parent space and won't be included in the measure reporting or modifications.")
    next
  end

  # get the absoluteAzimuth for the surface so we can categorize it
  absoluteAzimuth =  OpenStudio::convert(s.azimuth,"rad","deg").get + s.space.get.directionofRelativeNorth + model.getBuilding.northAxis
  until absoluteAzimuth < 360.0
    absoluteAzimuth = absoluteAzimuth - 360.0
  end

  if facade == "North"
    next if not (absoluteAzimuth >= 315.0 or absoluteAzimuth < 45.0)
  elsif facade == "East"
    next if not (absoluteAzimuth >= 45.0 and absoluteAzimuth < 135.0)
  elsif facade == "South"
    next if not (absoluteAzimuth >= 135.0 and absoluteAzimuth < 225.0)
  elsif facade == "West"
    next if not (absoluteAzimuth >= 225.0 and absoluteAzimuth < 315.0)
  else
    runner.registerError("Unexpected value of facade: " + facade + ".")
    return false
  end

  #get surface area adjusting for zone multiplier
  space = s.space
  if not space.empty?
    zone = space.get.thermalZone
  end
  if not zone.empty?
    zone_multiplier = zone.get.multiplier
    if zone_multiplier > 1
    end
  else
    zone_multiplier = 1 #space is not in a thermal zone
  end
  surface_gross_area = s.grossArea * zone_multiplier

  #loop through sub surfaces and add area including multiplier
  ext_window_area = 0
  s.subSurfaces.each do |subSurface| #onlky one and should have multiplier of 1
    ext_window_area = ext_window_area + subSurface.grossArea * subSurface.multiplier * zone_multiplier
  end

  final_gross_ext_wall_area += surface_gross_area
  final_ext_window_area += ext_window_area
end #end of surfaces.each do

Right after the line that checks to see if outsideBoundaryCondition == "Outdoors" you could add this code.

 zValueArray = []

 # get the existing vertices
 vertices = s.vertices
 vertices.each do |vertex|
   # push z value to array
   zValueArray << vertex.z
 end

 #skip if fails test
 test_height = 6 # feet
 next if zValueArray.max - zValueArray.min > OpenStudio::convert(test_height,"ft","m").get

The original Window to Wall Ratio measure does just look at surface orientation along with surface type, but you can really filter any way you want to. This could be based on surface, space, building story, or space type name, or some other attribute of one of those objects.

When we made the AEDG measures we had added the plenum object to OpenStudio so those fenestration measures do skip plenums, but it figures out the plenum by a user specified standards space type (more reliable then just using the name of a space type). The office and school have different logic on the size of the window based on how the guides were written. This includes a customized version of what is north, south, east, west vs. the way our basic measure works (which splits at the 45 degrees).

AEDG Small to Medium Office - Fenestration and Daylighting Controls

AEDG K12 - Fenestration and Daylighting Controls

Below I pasted in a block of code from our basic measure. It loops through each surafces without regard to which space they come from, but it could very easily be changed to first loop through spaces or even space types, and then for each space it could loop through surfaces.

You could add any kind of logic to skip a space type such as what is below

next if not space_type.name.to_s.include? "plenum"

There is an OpenStudio option to check of a zone is a plenum, but that would only be useful after the HVAC system has been added, which typically would be after fenestration is created. Any sort of name or space type filter requires the user to take some action to identify spaces that they later intend to use as plenums. One alternate solution would be to keep the logic similar to what is in the main block below, but check each surface to see that it is higher than a target test height. This could be a hard coded height or could be a user argument. This would work without much prior thought from the modeler, other than what would be typical for a plenum.

 #data for final condition wwr
surfaces = model.getSurfaces
surfaces.each do |s|
  next if not s.surfaceType == "Wall"
  next if not s.outsideBoundaryCondition == "Outdoors"
  if s.space.empty?
    runner.registerWarning("#{s.name} doesn't have a parent space and won't be included in the measure reporting or modifications.")
    next
  end

  # get the absoluteAzimuth for the surface so we can categorize it
  absoluteAzimuth =  OpenStudio::convert(s.azimuth,"rad","deg").get + s.space.get.directionofRelativeNorth + model.getBuilding.northAxis
  until absoluteAzimuth < 360.0
    absoluteAzimuth = absoluteAzimuth - 360.0
  end

  if facade == "North"
    next if not (absoluteAzimuth >= 315.0 or absoluteAzimuth < 45.0)
  elsif facade == "East"
    next if not (absoluteAzimuth >= 45.0 and absoluteAzimuth < 135.0)
  elsif facade == "South"
    next if not (absoluteAzimuth >= 135.0 and absoluteAzimuth < 225.0)
  elsif facade == "West"
    next if not (absoluteAzimuth >= 225.0 and absoluteAzimuth < 315.0)
  else
    runner.registerError("Unexpected value of facade: " + facade + ".")
    return false
  end

  #get surface area adjusting for zone multiplier
  space = s.space
  if not space.empty?
    zone = space.get.thermalZone
  end
  if not zone.empty?
    zone_multiplier = zone.get.multiplier
    if zone_multiplier > 1
    end
  else
    zone_multiplier = 1 #space is not in a thermal zone
  end
  surface_gross_area = s.grossArea * zone_multiplier

  #loop through sub surfaces and add area including multiplier
  ext_window_area = 0
  s.subSurfaces.each do |subSurface| #onlky one and should have multiplier of 1
    ext_window_area = ext_window_area + subSurface.grossArea * subSurface.multiplier * zone_multiplier
  end

  final_gross_ext_wall_area += surface_gross_area
  final_ext_window_area += ext_window_area
end #end of surfaces.each do

Right after the line that checks to see if outsideBoundaryCondition == "Outdoors" you could add this code.

 zValueArray = []

 # get the existing vertices
 vertices = s.vertices
 vertices.each do |vertex|
   # push z value to array
   zValueArray << vertex.z
 end

 #skip if fails test
 test_height = 6 # feet
 next if zValueArray.max - zValueArray.min > < OpenStudio::convert(test_height,"ft","m").get