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

Switch from facade area estimation to calculation #570

Closed
wants to merge 11 commits into from

Conversation

marcusfuchs
Copy link
Contributor

For #569.

This implements moving away from estimating the facade area for office buildings and instead calculating it from the building circumference and height. I think that this better represents the building described by the input data. In order to continue support for window_layout = 0, I kept the original estimation of outer wall and window areas, calculate the share of each and use this to redistribute the new facade area between walls and windows. (Nevertheless, I still (see #559) have doubts about whether window_layout = 0 is a good default value).

In the changed test results, you can see that this can cause significant changes in calculated outer wall and window area for some setups, with possibly far reaching consequences for calculated heating and cooling demands. That's why I think it would be great if @mlauster @PRemmen and @MichaMans could agree on whether to merge this as-is or find an alternative way forward.

@coveralls
Copy link

coveralls commented Mar 8, 2019

Coverage Status

Coverage decreased (-0.02%) to 96.623% when pulling 7e16044 on issue569_facade into d76e9fb on development.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.0009%) to 96.639% when pulling 4d2a635 on issue569_facade into d76e9fb on development.

@PRemmen
Copy link
Member

PRemmen commented Mar 13, 2019

@marcusfuchs thanks for that PR. I haven't looked into it yet, neither I followed the discussion yet :) give us please some more time to evaluate it at our institute

@marcusfuchs
Copy link
Contributor Author

@PRemmen No worries, I appreciate your short note that you have noticed the PR and that you're going to look at it - looking forward to your feedback.

@mlauster
Copy link
Contributor

I'm a bit concerned about omitting the statistical basis. The geometrical shapes are thought as an optional refinement and I'm not sure about the background studies that developed the metrics.
I would suggest to do it similarly to the windows:

  • Define a default shape that represents the statistical mean
  • Allow choosing other options such as quadratic and apply in this case the est_width and est_length to calculate the envelope surfaces

@marcusfuchs
Copy link
Contributor Author

marcusfuchs commented Mar 15, 2019

After discussing with @mlauster, we agreed that the statistical estimation of the facade area can be helpful if nothing is known about the geometry of the building (especially the shape of the building's footprint). The current code makes assumptions about the shape of the building's footprint via the office_layout parameter. Furthermore, its default value may not be ideal (a quadratic footprint may be better than the potentially problematic rectangular shapes of layout values 1 and 2).

I think one possible way to fix this quickly could be to redesign the role of the office_layout parameter:

if office_layout is None:
==> Use correlation
else:
==> Use calculation

In future work beyond this PR's scope, I would even suggest to think about:

  • Moving the geometry calculation out of the archetypes into a general setup
  • Open up the possibility to set the actual footprint geometry

@MichaMans
Copy link
Contributor

@mlauster @marcusfuchs How do we handle this now? I thought we agreed on an additional feature, so all implementations on the test side should be addition and not really changes? Or what was the actual agreement on that?

@marcusfuchs
Copy link
Contributor Author

@MichaMans If I remember correctly, I have so far only discussed this with @mlauster and from this I suggested the solution outlined above. Before continuing, I was waiting for feedback from you and @PRemmen to make sure we all agree on how to proceed.

@MichaMans
Copy link
Contributor

@marcusfuchs ok. As far as i understand it here, you already suggested an possible implementation with the office_layout parameter. I like this suggestion. It leads to the archetype usage as it is currently implemented with an additional new feature. So as a first solution i would go with that implementation. leading to addition checks for passing not None and using actual values for the length and width. In general i also like the idea of moving the geometrical calculation out of the archetype to be more flexibel and general

@PRemmen
Copy link
Member

PRemmen commented Mar 26, 2019

Also very much agree to this:

if office_layout is None:
==> Use correlation
else:
==> Use calculation

I'd be in favour of using None as the default value then.

In addition I really like the idea of TEASERs buildings being more "geometric". Maybe I'll start an implementation once I have a little time to do some hacking :)

@marcusfuchs
Copy link
Contributor Author

marcusfuchs commented Apr 12, 2019

We are again looking into this and noticed one more problem:

We agreed to go with

if office_layout is None:
==> Use correlation
else:
==> Use calculation

The motivation behind keeping the correlation was to use this when we do not know anything about the building footprint. So office_layout is supposed to mean the following:

None: "I don't know anything about the building footprint"
1: One side of the building is fixed at 13 m
2: One side of the building is fixed at 15 m
3: The building has a quadratic footprint

Now once we have calculated the total facade area either via the correlation or via the calculation, we later have to assign shares of the total facade area to each orientation. When we agreed that office_layout is None is different from e.g. office_layout = 3, we imply that the None case does not have a quadratic footprint. Then how do we determine which share of the total area is assigned to each orientation? If we assign them equally, we imply that in reality None means "use a quadratic footprint and estimate the facade area" while 3 means "use a quadratic footprint and calculate the facade area". This is not ideal, but we can implement it like this. To mitigate the problem a bit, we would use 3 as the default value, so None is only for people who explicitly want to use the correlation. Is that OK with everybody or do you have a better idea?

Switch from facade area estimation to calculation
@marcusfuchs marcusfuchs mentioned this pull request May 9, 2019
@marcusfuchs
Copy link
Contributor Author

@PRemmen @MichaMans This has been lying around for a long time. Before we pick it up again: Any opinions to my question above?

@MichaMans
Copy link
Contributor

@marcusfuchs thanks for bringing that up again. I'm not sure if I understand the problem here right and so I am a bit confused here (definitively need a second opinion from @PRemmen ), but my opinion on your question:

  1. we agreed on keeping the default archetype generation as it is correct?
  2. If so, currently 1 and 0/None is the same, or? Using 13 m width? So this would be the default case
  3. Is it not possible to use the current default facade area calculation and the assigning to every orientation like it is as default now?

@marcusfuchs
Copy link
Contributor Author

@MichaMans

  1. I am not sure, but I thought we would be OK with changing the default. In my opinion, assuming a quadratic footprint will be much more likely to give users without further knowledge a building representation they expect than fixing one side to 13 m
  2. Yes, 0/None and 1 are currently the same. Yet, I would suggest to change this so that 0 is no longer accepted and None implements something like 3 but with the old estimation of the facade area.
  3. It would be possible - yet I would argue that actually calculating the correct facade area would be a better default for many users.

@PRemmen
Copy link
Member

PRemmen commented Oct 14, 2019

sorry :) but I am a bit lost.

Why do we need "None" at all? currently 0 stands for None, right? And we have this:

if self.office_layout == 0 or self.office_layout == 1:
      self._est_width = 13.0
elif self.office_layout == 2:
      self._est_width = 15.0
 elif self.office_layout == 3:
      self._est_width = math.sqrt((self.net_leased_area /
                                         self.number_of_floors) *
                                       self.gross_factor)

So what would actually be None

Sorry, what I wrote is useless as @marcusfuchs already discussed it.

Changing default values is okay for me, BUT really needs to be integrated in all documention and release infos.

In addition, shouldn't we change from 0, 1, 2, 3 to something more "describing" e. g.:

- 1: "elongated_1_floor"
- 2: "elongated_2_floor"
- 3: "quadratic"

@PRemmen
Copy link
Member

PRemmen commented Aug 11, 2020

Although this is really old and never has been merge, I'd like to come back to this issue. @marcusfuchs @MichaMans

I implemented for myself a simple approach to calculate geometry based on footprints (e. g. from GIS data). https://github.com/RWTH-EBC/TEASER/tree/pre_private

Disclaimer: this is just a solution for myself and not documented and widely tested (thats why the branch is called pre_private ;) )

I had to add some new attributes to Office

self.outer_wall_gml = {
            "Wall1": {"area": None, "orientation": None, "tilt": 90},
            "Wall2": {"area": None, "orientation": None, "tilt": 90},
            "Wall3": {"area": None, "orientation": None, "tilt": 90},
            "Wall4": {"area": None, "orientation": None, "tilt": 90},
        }
self.roof_gml = {"Roof": {"area": None, "orientation": -1, "tilt": 0}}
self.ground_floor_gml = {
            "Ground Floor": {"area": None, "orientation": -2, "tilt": 0}
        }
self.window_gml = {
            "Window1": {"area": None, "orientation": None, "tilt": 90},
            "Window2": {"area": None, "orientation": None, "tilt": 90},
            "Window3": {"area": None, "orientation": None, "tilt": 90},
            "Window4": {"area": None, "orientation": None, "tilt": 90},
        }

as well as a new function to office called generate_gml.

It is now possible to fill the new attributes with what ever data (GIS, DWG-Drawings, CityGML) you want.

I implemented a small example using Django and GeoDjango, where building_energy is the SQL Mapping of 3DCityDB and bldg is the TEASER instance of a building.

import math
from django.contrib.gis.geos import LineString

footprint = (
    building_energy.bldg_thematic_surface.first()
    .thematic_surface_geom.first()
    .geometry
)
bldg.net_leased_area = (
    footprint.area * int(building_energy.storeys_above_ground) * 0.9
)

multi_line = []
for ring in footprint:
    for i, point in enumerate(ring):
        try:
            multi_line.append(LineString(point, ring[i + 1]))
        except IndexError:
            pass
outer_wall_gml = {}
window_gml = {}
for i, line in enumerate(multi_line):

    outer_wall_gml["Wall_{}".format(i)] = {
        area": (line.length * building_energy.measured_height) * (1- bldg.factor_win_gml),
        "orientation": _get_orientation(line),
        "tilt": 90,
    }
    window_gml["Window_{}".format(i)] = {
        "area": (line.length * building_energy.measured_height)
        * bldg.corr_factor_win,
        "orientation": _get_orientation(line),
        "tilt": 90,
    }

roof_gml = {"Roof": {"area": footprint.area, "orientation": -1, "tilt": 0}}
ground_floor_gml = {
    "Ground Floor": {"area": footprint.area, "orientation": -2, "tilt": 0}
}

bldg.outer_wall_gml = outer_wall_gml
bldg.window_gml = window_gml
bldg.roof_gml = roof_gml
bldg.ground_floor_gml = ground_floor_gml

bldg.generate_gml()

Orientation are mapped with following function:

def _get_orientation(line):

    normal = math.atan2((line[1][1] - line[0][1]), (line[1][0] - line[0][0])) * (
        180 / math.pi
    )

    if -180 < normal < 0:
        return round(-normal, 0)
    elif 0 < normal < 180:
        return round(360 - normal, 0)
    elif normal == 0 or normal == 180:
        return round(normal, 0)

probably there are even ways to do this more efficiently. If there is some interest using this in TEASER, we'd discuss what steps are necessary

@marcusfuchs
Copy link
Contributor Author

@PRemmen Thanks for reviving this! I think your approach looks very promising - would be happy to discuss the steps to add this to TEASER.

@PRemmen
Copy link
Member

PRemmen commented Sep 24, 2020

closed and will be done in #657

@PRemmen PRemmen closed this Sep 24, 2020
@MartinRaetz
Copy link
Contributor

@PRemmen Please delete the branch https://github.com/RWTH-EBC/TEASER/tree/issue569_facade if it is not used anymore.

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

7 participants