Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autogenerate skylight wells (redux) #17

Merged
merged 13 commits into from
Apr 17, 2024
Merged

Autogenerate skylight wells (redux) #17

merged 13 commits into from
Apr 17, 2024

Conversation

brgix
Copy link
Member

@brgix brgix commented Mar 19, 2024

Long overdue follow-up to an earlier (draft) PR on autogenerating skylight wells, e.g. through (unenclosed/unconditioned) attics or (indirectly-conditioned) plenums.

There are many more roof/ceiling geometry combinations to test, areas in the code to refactor/optimize, etc. Yet tempus fugit; this will have to do for now ...

@brgix brgix added the enhancement New feature or request label Mar 19, 2024
@brgix brgix self-assigned this Mar 19, 2024
box
end

##
# Generates a bounded box within a polygon. Returns a ULC sequence if original
# points are counterclockwise.
# Generates a BLC bounded box within a polygon.
Copy link
Member Author

@brgix brgix Mar 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a bounding box (in blue) circumscribes a set of vertices (e.g. the irregular polygon in white), the latter's bounded box is the largest rectangular polygon (in green) that fits within it.
bounded
The method is not fully optimized, yet yields satisfactory results for the following purposes:

  • (a more intuitive) re-alignment of irregular horizontal surfaces (e.g. floors, ceilings)
  • delineating a regular 2D drawing board (within a surface) for adding subsurfaces, skylight well arrays, etc.

h = height(pts)
d = h > w ? h : w
sgs = {}
box = boundedBox(pts)
Copy link
Member Author

@brgix brgix Mar 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The solution rests on the boundedBox method, a means to re-align a flat (or pre-flattened) surface (e.g. via OpenStudio::Transformation.alignFace). The goal is to go from an aligned surface (e.g. SEB roof):
seb_aligned
...which would yield the following skylight insertion (far from great):
sloped
... to a more "natural" or "intuitive" (?) alignment along its bounded box:
OS_skyarray

# conflicts). Valid leader line anchors (set key :ld) need to be generated
# prior to calling the method (see genAnchors). By default, the method seeks
# to link leader line anchors to set :vtx (key) vertices (users can select
# another collection of vertices, e.g. tag == :box).
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leader line anchors are needed to safely circumscribe skylight well inserts.
office_wells
... if safely deployed, the integration can be seamless.
office_skies

bulk = bulk.get
fine = fine.get

# No overhangs/attics. Calculation of roof area for SRR% is more intuitive.
Copy link
Member Author

@brgix brgix Mar 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Models without plenums/attics (e.g. warehouses) are far easier to process (no wells).

warehouse

Here, the addSkylights method is instructed to:

  • alter only the "Bulk Storage" roof on the left (ignoring the "Fine Storage" roof on the right)
  • purge pre-existing skylight subsurfaces of the "Bulk Storage" roof
  • ... leaving the "Fine Storage" skylights as is
  • meet a 4% skylight-to-roof ratio (SRR%)
  • use 8' x 8' (industrial) skylights as a template

The solution first analyses the geometry of the candidate space(s) to toplight (e.g. convexity, aspect ratios) to determine the most suitable skylight distribution pattern (users can be picky and restrict candidate patterns). Here, the solution has determined that the "Bulk Storage" is deep/wide enough to accommodate a 2D array skylight distribution, whose parameters (e.g. number of rows and columns, skylight spacing) reflect general recommendations articulated here, often the basis of known codes and standards. The pattern would have been different for more geometrically-constrained spaces.

Once the rows and columns of skylights is established, the solution does a final adjustment of skylight width/depth (usually a contraction) to exactly meet the request 4% SRR%.

@brgix brgix mentioned this pull request Apr 4, 2024

t = OpenStudio::Transformation.alignFace(p1)

if v < 340
Copy link
Member Author

@brgix brgix Apr 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OSut's overlap relies on the OpenStudio.intersect function to extract a potential overlapping area (i.e. a polygon) shared between 2 intersecting polygons. TBD relies on OSut's overlap to detect conflicts when dealing with fenestrated subsurfaces with Frame & Divider frames (where widths are often fairly narrow, e.g. 3cm to 6cm). I'm unable to isolate why (maybe linked to this fix), but OpenStudio.intersect fails for intersection widths < 5cm for versions v3.2.1 through v3.3.0. It works fine for versions > v3.3.0 (in fact, it works for v3.0.0 as well). So here, I'm simply relaxing the test for v3.2.1 and v3.3.0, as I have no intention in developing a backwards-compatible workaround for something like 3cm frame widths (for older SDK versions) ... so user beware :]

@@ -3099,7 +3099,7 @@ def getNonCollinears(pts = nil, n = 0)
p3 = pts[i3]
v13 = p3 - p1
v12 = p2 - p1
next if v12.cross(v13).length < TOL
next if v12.cross(v13).length < TOL2
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is one of maybe several tweaks to ensure OSut doesn't red-flag surfaces that EnergyPlus would ultimately tolerate. The latter would accept/process surfaces having a width/length of my thumb (definitely not good, but hey). More to come, maybe.

srr = 0.04

# The method returns the GRA, calculated BEFORE adding skylights/wells.
rm2 = mod1.addSkyLights(model.getSpaces, {srr: srr})
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generates the following:

seb_sky

@@ -264,6 +264,7 @@ def genConstruction(model = nil, specs = {})
a[:clad][:d ] = d
a[:clad][:id ] = "OSut|#{mt}|#{format('%03d', d*1000)[-3..-1]}"

# TO DO: replace sheathing by mineral below a certain Uo factor.
Copy link
Member Author

@brgix brgix Apr 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A single sheathing material (between 2x drywall layers) is a proxy for an uninsulated stud wall cavity. This won't do however when the partition must be insulated. So a switch is needed (e.g. from sheathing to mineral insulation) for lower Uo factors. If not, CTF calculations will fail.

@@mats = {
material: {}, # generic, e.g. lightweight cladding over furring, fibreboard
Copy link
Member Author

@brgix brgix Apr 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A generic (default) material is retained to cover all lightweight cladding and sheathing needs. When assemblies are adequately insulated, there's no point dragging multiple fibre-based materials with subtle differences in properties.

d = 0.015
d = 0.100 if specs[:frame] == :medium
d = 0.200 if specs[:frame] == :heavy
d = 0.100 if u
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows one to switch from un/insulated partitions, massive 1x layer construction, etc.

# Typical uninsulated, framed cavity wall, suitable for light interzone
# assemblies (i.e. symmetrical, 3-layer construction).
specs = {type: :partition}
surface = cls1.genConstruction(model, specs)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of many (minimally-) commented genConstruction calls.

@brgix brgix merged commit 423510e into develop Apr 17, 2024
7 checks passed
@brgix brgix deleted the geo branch October 8, 2024 09:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant