Skip to content

Commit ab4bcf2

Browse files
authored
feat: convert windows to fenestration surfaces (#7)
1 parent aad6cac commit ab4bcf2

3 files changed

Lines changed: 183 additions & 105 deletions

File tree

R/conv-subsurface.R

Lines changed: 86 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -2,131 +2,113 @@
22
# TODO: handle window type
33
# WINDOW -> FenestrationSurface:Detailed
44
destep_conv_window <- function(dest, ep) {
5-
return(dest)
6-
# TODO: Does DeST support polygon windows other than rectangles?
7-
8-
DBI::dbGetQuery(
9-
dest,
10-
"
11-
SELECT
12-
E.ENCLOSE_ID AS ENCLOSE_ID,
13-
S.SURFACE_ID AS SURFACE_ID,
14-
S.NAME AS SURFACE_NAME
15-
FROM (
16-
-- get both side surfaces
17-
SELECT ID AS ENCLOSE_ID, SIDE1 AS SURFACE_ID FROM MAIN_ENCLOSURE
18-
UNION
19-
SELECT ID AS ENCLOSE_ID, SIDE2 AS SURFACE_ID FROM MAIN_ENCLOSURE
20-
) E
21-
LEFT JOIN SURFACE S
22-
ON E.SURFACE_ID = S.SURFACE_ID
23-
"
24-
)
25-
26-
DBI::dbListFields(dest, "SURFACE")
27-
DBI::dbGetQuery(dest, "SELECT * FROM SURFACE", n = 5)
28-
DBI::dbGetQuery(dest, "SELECT NAME FROM WINDOW", n = 5)
29-
30-
DBI::dbGetQuery(
31-
dest,
32-
n = 5,
33-
"
34-
SELECT
35-
W.ID AS ID,
36-
W.NAME AS NAME,
37-
W.TYPE AS TYPE,
38-
S.SURFACE_NAME AS SURFACE_NAME
39-
FROM WINDOW W
40-
LEFT JOIN (
41-
-- get surface name
42-
SELECT
43-
E.ENCLOSE_ID AS ENCLOSE_ID,
44-
SR.SURFACE_ID AS SURFACE_ID,
45-
SR.NAME AS SURFACE_NAME
46-
FROM (
47-
SELECT ID AS ENCLOSE_ID, SIDE1 AS SURFACE_ID FROM MAIN_ENCLOSURE
48-
UNION
49-
SELECT ID AS ENCLOSE_ID, SIDE2 AS SURFACE_ID FROM MAIN_ENCLOSURE
50-
) E
51-
LEFT JOIN SURFACE SR
52-
ON E.SURFACE_ID = SR.SURFACE_ID
53-
) S
54-
ON W.OF_ENCLOSURE = S.ENCLOSE_ID
55-
"
56-
)
5+
if (!destep_has_rows(dest, "WINDOW")) return(NULL)
576

58-
DBI::dbGetQuery(
7+
# TODO: Does DeST support polygon windows other than rectangles?
8+
window <- DBI::dbGetQuery(
599
dest,
60-
n = 5,
6110
"
62-
SELECT
63-
W.ID AS ID,
64-
W.NAME AS NAME,
65-
W.TYPE AS TYPE,
66-
S.SURFACE_NAME AS SURFACE_NAME
67-
FROM WINDOW W
68-
LEFT JOIN (
69-
-- get surface name
11+
WITH WIN_CONST AS (
7012
SELECT
71-
E.ENCLOSE_ID AS ENCLOSE_ID,
72-
SR.SURFACE_ID AS SURFACE_ID,
73-
SR.NAME AS SURFACE_NAME
74-
FROM (
75-
-- get both side surfaces
76-
SELECT ID AS ENCLOSE_ID, SIDE1 AS SURFACE_ID FROM MAIN_ENCLOSURE
77-
UNION
78-
SELECT ID AS ENCLOSE_ID, SIDE2 AS SURFACE_ID FROM MAIN_ENCLOSURE
79-
) E
80-
LEFT JOIN SURFACE SR
81-
ON E.SURFACE_ID = SR.SURFACE_ID
82-
) S
83-
ON W.OF_ENCLOSURE = S.ENCLOSE_ID
84-
"
85-
)
86-
87-
DBI::dbGetQuery(
88-
dest,
89-
n = 5,
90-
"
13+
W.ID,
14+
CASE
15+
WHEN W.WINDOW_CONSTRUCTION != 0 THEN W.WINDOW_CONSTRUCTION
16+
ELSE D.LONG
17+
END AS WINDOW_CONSTRUCTION
18+
FROM WINDOW W
19+
LEFT JOIN DEFAULT_SETTING D
20+
ON W.WINDOW_CONSTRUCTION = 0 AND
21+
D.TABLE_NAME = 'WINDOW' AND D.FIELD_NAME = 'WINDOW_CONSTRUCTION' AND D.TYPE = 2
22+
)
9123
SELECT
9224
W.ID AS ID,
9325
W.NAME AS NAME,
9426
W.TYPE AS TYPE,
9527
SW.CNAME AS CONSTRUCTION,
96-
S.SURFACE_NAME AS SURFACE_NAME,
28+
CASE
29+
WHEN S1.TYPE = 0 THEN S1.NAME
30+
WHEN S2.TYPE = 0 THEN S2.NAME
31+
ELSE COALESCE(S1.NAME, S2.NAME)
32+
END AS SURFACE_NAME,
33+
CASE
34+
WHEN S1.TYPE = 0 THEN 1
35+
WHEN S2.TYPE = 0 THEN 2
36+
ELSE 1
37+
END AS SIDE,
9738
L.POINT_NO AS POINT_NO,
9839
ROUND(P.X, 3) AS POINT_X,
9940
ROUND(P.Y, 3) AS POINT_Y,
10041
ROUND(P.Z, 3) AS POINT_Z
10142
FROM WINDOW W
102-
LEFT JOIN (
103-
-- get surface name
104-
SELECT
105-
S.SURFACE_ID AS SURFACE_ID,
106-
S.NAME AS SURFACE_NAME
107-
FROM (
108-
-- get both side surfaces
109-
SELECT SIDE1 AS SURFACE_ID, NAME AS SURFACE_NAME FROM MAIN_ENCLOSURE
110-
UNION
111-
SELECT SIDE2 AS SURFACE_ID, NAME AS SURFACE_NAME FROM MAIN_ENCLOSURE
112-
) E
113-
LEFT JOIN SURFACE S
114-
ON E.SURFACE_ID = S.SURFACE_ID
115-
) S
116-
ON W.OF_ENCLOSURE = S.SURFACE_ID
43+
LEFT JOIN MAIN_ENCLOSURE E
44+
ON W.OF_ENCLOSURE = E.ID
45+
LEFT JOIN SURFACE S1
46+
ON E.SIDE1 = S1.SURFACE_ID
47+
LEFT JOIN SURFACE S2
48+
ON E.SIDE2 = S2.SURFACE_ID
49+
LEFT JOIN WIN_CONST WC
50+
ON W.ID = WC.ID
11751
LEFT JOIN SYS_WINDOW SW
118-
ON W.ID = SW.WINDOW_ID
119-
LEFT JOIN PLANE P
120-
ON W.MIDDLE_PLANE = P.PLANE_ID
52+
ON WC.WINDOW_CONSTRUCTION = SW.WINDOW_ID
53+
LEFT JOIN PLANE PL
54+
ON W.MIDDLE_PLANE = PL.PLANE_ID
12155
LEFT JOIN GEOMETRY G
122-
ON P.GEOMETRY = G.GEOMETRY_ID
56+
ON PL.GEOMETRY = G.GEOMETRY_ID
12357
LEFT JOIN LOOP_POINT L
12458
ON G.BOUNDARY_LOOP_ID = L.LOOP_ID
12559
LEFT JOIN POINT P
12660
ON L.POINT = P.POINT_ID
61+
ORDER BY W.ID, L.POINT_NO
12762
"
12863
)
12964

130-
assert_unique_name(surface$NAME[surface$POINT_NO == 0L], "surface")
131-
data.table::setDT(surface)
65+
assert_unique_name(window$NAME[window$POINT_NO == 0L], "window")
66+
data.table::setDT(window)
67+
68+
# Match the parent wall orientation used by destep_conv_surface().
69+
window[SIDE == 2L, by = "ID", `:=`(
70+
POINT_X = rev(POINT_X), POINT_Y = rev(POINT_Y), POINT_Z = rev(POINT_Z)
71+
)]
72+
73+
value <- window[,
74+
by = "ID",
75+
list(value = list(c(
76+
list(
77+
# 01: Name
78+
name = NAME[[1L]],
79+
# 02: Surface Type
80+
surface_type = "Window",
81+
# 03: Construction Name
82+
construction_name = CONSTRUCTION[[1L]],
83+
# 04: Building Surface Name
84+
building_surface_name = SURFACE_NAME[[1L]],
85+
# 05: Outside Boundary Condition Object
86+
outside_boundary_condition_object = NULL,
87+
# 06: View Factor to Ground
88+
view_factor_to_ground = NULL,
89+
# 07: Frame and Divider Name
90+
frame_and_divider_name = NULL,
91+
# 08: Multiplier
92+
multiplier = NULL,
93+
# 09: Number of Vertices
94+
number_of_vertices = max(POINT_NO) + 1L
95+
),
96+
# Vertices
97+
as.list(as.double(vapply(POINT_NO + 1L,
98+
FUN.VALUE = double(3),
99+
function(ind) {
100+
c(POINT_X[ind], POINT_Y[ind], POINT_Z[ind])
101+
}
102+
)))
103+
)))
104+
]$value
105+
106+
out <- eval(as.call(c(
107+
destep_add, dest, ep,
108+
lapply(value, function(val) bquote("FenestrationSurface:Detailed" := .(val)))
109+
)))
110+
111+
attr(out, "table") <- window
112+
113+
out
132114
}

R/conv.R

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ to_eplus <- function(dest, ver = "latest", copy = TRUE, verbose = FALSE) {
163163
building = destep_conv_building(tmpdb, ep),
164164
zone = destep_conv_zone(tmpdb, ep),
165165
surface = destep_conv_surface(tmpdb, ep),
166-
# window = destep_conv_window(tmpdb, ep)
166+
window = destep_conv_window(tmpdb, ep),
167167
const = destep_conv_const(tmpdb, ep),
168168
schedule = destep_conv_schedule(tmpdb, ep)
169169
)
@@ -174,6 +174,7 @@ to_eplus <- function(dest, ver = "latest", copy = TRUE, verbose = FALSE) {
174174
))) {
175175
conv$internal_gains <- destep_conv_internal_gains(tmpdb, ep)
176176
}
177+
conv <- Filter(Negate(is.null), conv)
177178

178179
# update rleid
179180
num_obj <- 0L

tests/testthat/test-conv-window.R

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
test_that("can convert 'WINDOW'", {
2+
ep <- ensure_empty_idf()
3+
dest <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
4+
on.exit(DBI::dbDisconnect(dest), add = TRUE)
5+
6+
DBI::dbWriteTable(dest, "DEFAULT_SETTING", data.frame(
7+
TABLE_NAME = character(),
8+
FIELD_NAME = character(),
9+
TYPE = integer(),
10+
LONG = integer()
11+
))
12+
DBI::dbWriteTable(dest, "SURFACE", data.frame(
13+
SURFACE_ID = c(10L, 20L),
14+
NAME = c("Outside Face", "Room Wall"),
15+
TYPE = c(1L, 0L)
16+
))
17+
DBI::dbWriteTable(dest, "MAIN_ENCLOSURE", data.frame(
18+
ID = 100L,
19+
SIDE1 = 10L,
20+
SIDE2 = 20L
21+
))
22+
DBI::dbWriteTable(dest, "SYS_WINDOW", data.frame(
23+
WINDOW_ID = 4L,
24+
CNAME = "Double Window"
25+
))
26+
DBI::dbWriteTable(dest, "WINDOW", data.frame(
27+
ID = 200L,
28+
NAME = "Window A",
29+
TYPE = 35L,
30+
OF_ENCLOSURE = 100L,
31+
MIDDLE_PLANE = 300L,
32+
WINDOW_CONSTRUCTION = 4L
33+
))
34+
DBI::dbWriteTable(dest, "PLANE", data.frame(
35+
PLANE_ID = 300L,
36+
GEOMETRY = 400L
37+
))
38+
DBI::dbWriteTable(dest, "GEOMETRY", data.frame(
39+
GEOMETRY_ID = 400L,
40+
BOUNDARY_LOOP_ID = 500L
41+
))
42+
DBI::dbWriteTable(dest, "LOOP_POINT", data.frame(
43+
LOOP_ID = 500L,
44+
POINT_NO = 0:3,
45+
POINT = 1:4
46+
))
47+
DBI::dbWriteTable(dest, "POINT", data.frame(
48+
POINT_ID = 1:4,
49+
X = c(1, 2, 2, 1),
50+
Y = c(0, 0, 0, 0),
51+
Z = c(1, 1, 3, 3)
52+
))
53+
54+
expect_type(window <- destep_conv_window(dest, ep), "list")
55+
expect_named(window, c("object", "value"))
56+
expect_equal(unique(window$object$class_name), "FenestrationSurface:Detailed")
57+
expect_s3_class(attr(window, "table"), "data.table")
58+
expect_equal(unique(attr(window, "table")$SURFACE_NAME), "Room Wall")
59+
expect_equal(unique(attr(window, "table")$CONSTRUCTION), "Double Window")
60+
expect_equal(attr(window, "table")$POINT_Z, c(3, 3, 1, 1))
61+
})
62+
63+
test_that("skips window conversion without WINDOW records", {
64+
ep <- ensure_empty_idf()
65+
dest <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
66+
on.exit(DBI::dbDisconnect(dest), add = TRUE)
67+
68+
expect_null(destep_conv_window(dest, ep))
69+
})
70+
71+
test_that("can convert windows from a real DeST model", {
72+
skip_on_cran()
73+
74+
ep <- ensure_empty_idf()
75+
src <- ensure_dest_sqlite_file()
76+
on.exit(DBI::dbDisconnect(src), add = TRUE)
77+
78+
path_tmp <- tempfile(fileext = ".sql")
79+
dest <- DBI::dbConnect(RSQLite::SQLite(), path_tmp)
80+
on.exit({
81+
DBI::dbDisconnect(dest)
82+
unlink(path_tmp)
83+
}, add = TRUE)
84+
RSQLite::sqliteCopyDatabase(src, dest)
85+
destep_update_name(dest)
86+
87+
window <- destep_conv_window(dest, ep)
88+
tab <- attr(window, "table")
89+
90+
expect_equal(unique(window$object$class_name), "FenestrationSurface:Detailed")
91+
expect_equal(nrow(window$object), DBI::dbGetQuery(dest, "SELECT COUNT(*) AS N FROM WINDOW")$N)
92+
expect_false(anyNA(tab$SURFACE_NAME))
93+
expect_false(anyNA(tab$CONSTRUCTION))
94+
expect_true(all(tab$POINT_NO %in% 0:3))
95+
})

0 commit comments

Comments
 (0)