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

Adding geometry-based methods #13

Merged
merged 43 commits into from Oct 16, 2023
Merged

Adding geometry-based methods #13

merged 43 commits into from Oct 16, 2023

Conversation

brgix
Copy link
Member

@brgix brgix commented May 28, 2023

This builds upon the previous geometry PR towards automating sub surface generation (e.g. skylights). As a follow-up, this PR deals with automated well (or shaft) generation for skylights (or dormers, or roof monitors) designed to daylight occupied zones more than one floor below (e.g. wells completely spanning unoccupied plenums or attics, and/or multiple floors). For a single array of skylights, this involves inter alia:

  • cutting out a hole within an outdoor-facing surface to accommodate a new (smaller) base surface
  • (each array of skylights gets a new base surface)
  • generating a vertical well linking each new base surface to a selected space's ceiling
  • ensuring everything fits (beforehand)
  • cutting out holes for both receiving ceiling and its adjacent floor
  • (repeating the exercise for any other spanned ceiling/floor duo)
  • splitting vertical well walls to accommodate other spanned spaces (e.g. ensuring adjacencies)
  • group adjacent wells (as a single well)
well

The Figure illustrates a simplified version of the US DOE SmallOffice Prototype model (overhangs are left out), with an added skylights/well combo. The suggested implementation would raise a number of red flags for many experienced OpenStudio/EnergyPlus users/devs, notably concerning:

  • surfaces cut out within a surface
  • concavity of surfaces and spaces/zones

... affecting several key OpenStudio/EnergyPlus calculations:

  • autocalculated surface areas and space/zone volumes
  • shadows casted by concave surfaces
  • shadows received by concave surfaces
  • solar distribution within concave spaces/zones (with interior reflections)
  • long-wave radiation distribution within concave spaces/zones

By the end of this PR, it is hoped (!) that most of these challenges will be addressed/documented (if not solved). For instance, PixelCounting solves a large number of solar-related challenges (yet at a cost).

@brgix brgix self-assigned this May 28, 2023
# calculations (and avoid OpenStudio stdout errors/warnings), append the
# last vertex of the original surface: each EnergyPlus edge must be
# referenced (at least) twice (i.e. the 'leader line' between each of the
# 3x original surfaces and each of the 'mini' holes must be doubled).
Copy link
Member Author

@brgix brgix Jul 27, 2023

Choose a reason for hiding this comment

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

As a first test, the US DOE SmallOffice Prototype core floor and ceiling (as well as its adjacent attic floor) are cut out to each receive a 2m x 2m mini surface insert. The 3x original (larger) surfaces must have their vertices extended to accommodate their smaller mini counterparts, i.e. holes:

top

Vertex winding for both the (larger) core and attic floors: a clockwise sequence for the outer edges (as seen from a bird's eye view), followed by a counterclockwise delineation of the mini hole (in the actual model, the opening is square and centred).

mini_attic_vtx << OpenStudio::Point3d.new(mini_w, mini_s, 3.05)
mini_attic_vtx << OpenStudio::Point3d.new(mini_w, mini_n, 3.05)
mini_attic = OpenStudio::Model::Surface.new(mini_attic_vtx, model)
mini_attic.setName("Mini attic")
Copy link
Member Author

@brgix brgix Jul 27, 2023

Choose a reason for hiding this comment

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

xtrafloor

The 2m x 2m mini surface centred in the attic floor. Here, the original floor (as well as its adjacent core ceiling) vertices are not yet extended (as described here). Although subsequent OpenStudio/EnergyPlus tests support this vertex extension operation, it does seem to prevent SketchUp from rendering such modified OpenStudio models. The OpenStudio Application renders the model just fine, yet this remains a challenge for SketchUp OpenStudio plugin users. Hopefully there's a workaround for this.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, SketchUp will detect this as an inner loop of the larger polygon, there is code that then runs to turn inner loops into subsurfaces (auto-classified as door, window, or skylight). Is that what you are seeing when you open this in SketchUp? It will be turned into a skylight? The way around that would be to add vertices to the outer polygon (like you did here #13 (comment)) so the smaller surface is technically adjacent and not "inside" the larger one.

Copy link
Member Author

@brgix brgix Jul 31, 2023

Choose a reason for hiding this comment

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

No, SketchUp (2021) has difficulty with the vertex sequencing I illustrate in #13 (comment). SketchUp is unable to render the OSM geometry altogether. If one runs these OSut Rake tests (geo branch), 3x OSM files of interest are generated under spec/files/osms/out:

  • mini.osm
  • mini2.osm
  • mini3.osm

None of these will render. Yet they render just fine with the OpenStudio Application (Geometry tab).

@@ -2708,8 +2712,9 @@ module M
expect(core.floorArea).to be_within(TOL).of(149.66)
core_volume = core.floorArea * 3.05
expect(core_volume).to be_within(TOL).of(core.volume)
expect(attic.volume).to be_within(TOL).of(720.19)
expect(attic.floorArea).to be_within(TOL).of(567.98)
expect(attic.volume).to be_within(TOL).of(720.19) unless v < 350
Copy link
Member Author

@brgix brgix Jul 27, 2023

Choose a reason for hiding this comment

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

Calculations of core and attic floor/ceiling surface areas (m2), as well as core and attic volumes (m3), remain consistent even with mini surfaces inserted in the centre of each. Reiterating that this requires sequencing vertices of the larger (original) surfaces, as described here. Simulation results remain consistent, regardless of Solar Distribution modes, as summarized here.

Copy link
Member

Choose a reason for hiding this comment

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

You should check the surface areas and zone volumes in the E+ results too. The reporting measure has an example here: https://github.com/NREL/openstudio-common-measures-gem/blob/develop/lib/measures/example_report/resources/os_lib_reporting_example.rb#L221 that shows how to query data out of the E+ tabular results. The eplusout.sql file has a table named tabulardatawithstrings which follows the tables in the eplustbl.htm file. If you adjust the ReportName, ReportForString, TableName, RowName, ColumnName, and Units in the query you can get any of the other data in the eplustbl.htm file like the "Envelope Summary" or "Zone Summary"

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for the pointer, @macumber. Reported areas/volumes in the eplusout.htm do match these first 3x test results. Once I'm done, I'll look into automating an SQL test.

# office.osm FullInteriorAndExterior 247 GJ 3.8 UMH cool
# mini.osm A FullInteriorAndExterior 247 GJ 4.0 UMH cool
# mini.osm B FullExteriorWithReflections 248 GJ 3.8 UMH cool
# mini.osm C FullInteriorAndExteriorWithReflections 247 GJ 3.8 UMH cool
Copy link
Member Author

Choose a reason for hiding this comment

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

Consistent results using E+ v22.2, no warnings or errors.

# Mini as an interior courtyard:
# - 4x new outdoor-facing walls (core)
# - remove mini floor @Z0 and mini ceiling @Z3.05
# - attic mini floor facing outdoors
Copy link
Member Author

@brgix brgix Jul 27, 2023

Choose a reason for hiding this comment

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

2nd test: This transforms the core space into a donut (i.e. a toroidal polytope), something considered problematic for OpenStudio. Not sure if this is strictly a v350 fix, but both area and volume calculations correctly reflect the intended changes - so do the E+ 22.2 simulation results.

# @param ratio [Double] internal mass surface / floor areas
#
# @return [Bool] true if successful
# @return [Bool] false if invalid input (see logs)
def genMass(model = nil, sps = [], ratio = 2.0)
# This is largely adapted from OpenStudio-Standards
def genMass(sps = OpenStudio::Model::SpaceVector.new, ratio = 2.0)
Copy link
Member Author

Choose a reason for hiding this comment

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

Switch from input Arrays to ObjectVectors, whenever possible. Lightens argument validation.

# poly method (convex = true, uniqueness = true, collinearity = false).
expect(vtx.size).to eq(3)
expect(mod1.poly(vtx, true, true, false).size).to eq(3)
expect(mod1.status.zero?).to be(true)
triads = mod1.getTriads(vtx)
expect(mod1.status.zero?).to be(true)
expect(triads.size).to eq(3)

# TO DO ... in progress.
Copy link
Member Author

Choose a reason for hiding this comment

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

Some of the geometry methods are in flux, and so are their tests.

Gemfile Outdated
@@ -1,3 +1,5 @@
source "https://rubygems.org"

gem "oslg", git: "https://github.com/rd2/oslg", branch: "yard"
Copy link
Member Author

Choose a reason for hiding this comment

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

Tests OSlg release candidate (passed).

door: 1.800, # insulated, unglazed steel door (single layer)
window: 2.800, # e.g. patio doors (simple glazing)
skylight: 3.500 # all skylight technologies
}.freeze
Copy link
Member Author

Choose a reason for hiding this comment

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

Formatted this way is great for Yard.


log(ERR, "Invalid '#{id}' MIN/MAX (#{mth})") unless res[:min] && res[:max]
res[:min] = values.min.is_a?(Numeric) ? values.min : nil
res[:max] = values.max.is_a?(Numeric) ? values.max : nil
Copy link
Member Author

Choose a reason for hiding this comment

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

A few instances of refactoring code (more compact, easier).


stpts = M.setpoints(entry)
expect(stpts[:heating].nil?).to be(false)
expect(stpts[:heating]).to be_within(TOL).of(22.78) # radiant heating
Copy link
Member Author

Choose a reason for hiding this comment

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

Adding a zone equipment temperature setpoint test (independent of zone thermostat temperature setpoint).

@@ -2880,6 +2881,9 @@ def overlaps?(p1 = nil, p2 = nil, flat = true)
return false if p1.empty?
return false if p2.empty?

return true if fits?(p1, p2)
return true if fits?(p2, p1)
Copy link
Member Author

@brgix brgix Sep 17, 2023

Choose a reason for hiding this comment

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

Simpler to catch fit cases sooner.

return true if delta > TOL
end

false
Copy link
Member Author

Choose a reason for hiding this comment

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

Revised logic. Catches unexpected (and unfortunately yet untested) cases where Boost-based join returns either polygon area for 2 side-by-side polygons.

# warning if aligned points aren't @Z =0, before 'flattening'.
#
# invalid("points (non-aligned)", mth, 1, WRN) unless xyz?(a, :z, 0)
a = flatten(a).to_a unless xyz?(a, :z, 0)
Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe better as a DEBUG log, but muting this for now. Upcoming methods will frequently need to project polygons unto each other (without sharing same 3D plane).

expect(surface.is_a?(OpenStudio::Model::LayeredConstruction)).to be(true)
expect(surface).to_not be_nil
expect(cls1.status).to be_zero
expect(surface).to be_a(OpenStudio::Model::LayeredConstruction)
Copy link
Member Author

Choose a reason for hiding this comment

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

General revision, making better use of RSpec methods. Easier to consult.


# --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- #
# CASE 2: None of the occupied spaces have outdoor-facing roofs, yet the
# plenum above has 4x outdoor-facing roofs (each matches 1x space ceiling).
Copy link
Member Author

Choose a reason for hiding this comment

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

getRoofs fetches both outdoor-facing RoofCeiling surfaces, as well as those of a plenum/attic directly above.

end
next unless overlaps?(ceiling, ruf)

roofs << ruf unless roofs.include?(ruf)
Copy link
Member Author

@brgix brgix Sep 17, 2023

Choose a reason for hiding this comment

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

overlaps? calls fits? - redundant.

@brgix brgix merged commit 362e0ac into develop Oct 16, 2023
6 checks passed
@brgix brgix mentioned this pull request Mar 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants