plan2eplus 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- plan2eplus/__init__.py +2 -0
- plan2eplus/airflow_network/airboundary.py +106 -0
- plan2eplus/airflow_network/creator.py +21 -0
- plan2eplus/airflow_network/logic.py +14 -0
- plan2eplus/airflow_network/modifiers.py +42 -0
- plan2eplus/analysis/analysis_air_boundary.py +75 -0
- plan2eplus/analysis/cp_eq.py +22 -0
- plan2eplus/analysis/dataframes.py +99 -0
- plan2eplus/analysis/dataframes2.py +49 -0
- plan2eplus/analysis/ep_wind_cp.cpp +41 -0
- plan2eplus/analysis/helpers.py +80 -0
- plan2eplus/analysis/materials_compare.py +47 -0
- plan2eplus/analysis/plan_details.py +31 -0
- plan2eplus/analysis/plot_helpers.py +89 -0
- plan2eplus/analysis/plot_subsurfaces.py +193 -0
- plan2eplus/analysis/pressure_on_network.py +85 -0
- plan2eplus/analysis/result_names.json +25 -0
- plan2eplus/analysis/time_plots.py +33 -0
- plan2eplus/analysis/volumes.py +70 -0
- plan2eplus/analysis2/all_cases_v_time.py +170 -0
- plan2eplus/case_edits/__init__.py +0 -0
- plan2eplus/case_edits/defaults.py +6 -0
- plan2eplus/case_edits/epcase.py +106 -0
- plan2eplus/case_edits/ezcase.py +104 -0
- plan2eplus/constructions/constructions.py +47 -0
- plan2eplus/constructions/materials.py +24 -0
- plan2eplus/constructions/organize.py +92 -0
- plan2eplus/constructions/unified_constructions.py +49 -0
- plan2eplus/experiments/comparisons.py +126 -0
- plan2eplus/experiments/dynamic_door_sched.py +141 -0
- plan2eplus/experiments/name_splits.py +58 -0
- plan2eplus/experiments/retrieve.py +53 -0
- plan2eplus/experiments/scatter.py +71 -0
- plan2eplus/helpers/dates.py +15 -0
- plan2eplus/helpers/ep_geom_helpers.py +69 -0
- plan2eplus/helpers/ep_helpers.py +149 -0
- plan2eplus/helpers/geometry_interfaces.py +103 -0
- plan2eplus/helpers/helpers.py +66 -0
- plan2eplus/helpers/output_requests.py +63 -0
- plan2eplus/helpers/plot_colors.py +39 -0
- plan2eplus/helpers/plots.py +92 -0
- plan2eplus/helpers/read_sql.py +34 -0
- plan2eplus/helpers/save_details +0 -0
- plan2eplus/helpers/variable_interfaces.py +78 -0
- plan2eplus/helpers/variables.py +96 -0
- plan2eplus/main.py +4 -0
- plan2eplus/network/cardinal_positions.py +33 -0
- plan2eplus/network/network.py +184 -0
- plan2eplus/network/visuals.py +71 -0
- plan2eplus/plan/graph_to_subsurfaces.py +111 -0
- plan2eplus/plan/helpers.py +23 -0
- plan2eplus/plan/interfaces.py +78 -0
- plan2eplus/plan/plan_to_eppy.py +30 -0
- plan2eplus/setup/data_wrangle.py +163 -0
- plan2eplus/setup/data_wrangle2.py +59 -0
- plan2eplus/setup/interfaces.py +28 -0
- plan2eplus/setup/materials_setup.py +37 -0
- plan2eplus/setup/plots.py +36 -0
- plan2eplus/setup/setup.py +77 -0
- plan2eplus/subsurfaces/constructions.py +20 -0
- plan2eplus/subsurfaces/creator.py +86 -0
- plan2eplus/subsurfaces/interfaces.py +82 -0
- plan2eplus/subsurfaces/logic.py +125 -0
- plan2eplus/subsurfaces/placement.py +67 -0
- plan2eplus/subsurfaces/visuals.py +26 -0
- plan2eplus-0.1.0.dist-info/METADATA +16 -0
- plan2eplus-0.1.0.dist-info/RECORD +69 -0
- plan2eplus-0.1.0.dist-info/WHEEL +4 -0
- plan2eplus-0.1.0.dist-info/entry_points.txt +2 -0
plan2eplus/__init__.py
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from eppy.bunch_subclass import EpBunch
|
|
3
|
+
from geomeppy import IDF
|
|
4
|
+
from helpers.helpers import key_from_value
|
|
5
|
+
from helpers.ep_helpers import find_zone_subsurfaces, get_partner_of_surface, get_surface_by_name, PARTNER
|
|
6
|
+
from plan.helpers import create_room_map, load_data_from_json
|
|
7
|
+
from plan.interfaces import GRAPH, GraphEdgeJSON
|
|
8
|
+
from subsurfaces.logic import PairOnly, find_surface_connecting_two_zones
|
|
9
|
+
from airflow_network.modifiers import add_zone, add_subsurface
|
|
10
|
+
|
|
11
|
+
# TODO see notes on how to make this better..
|
|
12
|
+
|
|
13
|
+
def get_airboundary_wall(airboundary: EpBunch):
|
|
14
|
+
n = airboundary.Name
|
|
15
|
+
remain = n.split(" ")[1:]
|
|
16
|
+
return " ".join(remain)
|
|
17
|
+
|
|
18
|
+
def handle_edge_airboundary(
|
|
19
|
+
e: GraphEdgeJSON,
|
|
20
|
+
room_map: dict[int, str],
|
|
21
|
+
):
|
|
22
|
+
source, target = e["source"], e["target"]
|
|
23
|
+
return PairOnly(key_from_value(room_map, source), key_from_value(room_map, target))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_airboundary_pairs_from_case(path_to_inputs: Path):
|
|
27
|
+
room_map = create_room_map(path_to_inputs)
|
|
28
|
+
graph_data = load_data_from_json(path_to_inputs, GRAPH)
|
|
29
|
+
edges: list[GraphEdgeJSON] = graph_data["links"]
|
|
30
|
+
return [
|
|
31
|
+
handle_edge_airboundary(e, room_map) for e in edges if e["details"]["id"] == 0
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
def update_air_boundary_constructions(idf: IDF, path_to_inputs: Path):
|
|
35
|
+
ab_pairs = get_airboundary_pairs_from_case(path_to_inputs)
|
|
36
|
+
for pair in ab_pairs:
|
|
37
|
+
surf = find_surface_connecting_two_zones(idf, pair)
|
|
38
|
+
assert surf
|
|
39
|
+
|
|
40
|
+
o = idf.newidfobject("CONSTRUCTION:AIRBOUNDARY")
|
|
41
|
+
o.Name = f"AirBoundary {surf.Name}"
|
|
42
|
+
idf = add_subsurface(idf, surf.Name)
|
|
43
|
+
surf.Construction_Name = o.Name
|
|
44
|
+
partner_surf = get_partner_of_surface(idf, surf)
|
|
45
|
+
assert partner_surf
|
|
46
|
+
partner_surf.Construction_Name = o.Name
|
|
47
|
+
|
|
48
|
+
return idf
|
|
49
|
+
|
|
50
|
+
def get_afn_zones(idf: IDF):
|
|
51
|
+
afn_zones = idf.idfobjects["AIRFLOWNETWORK:MULTIZONE:ZONE"]
|
|
52
|
+
assert afn_zones, "Subsurface AFN zones have not been added"
|
|
53
|
+
return [i.Zone_Name for i in afn_zones]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def update_afn_for_airboundary_zones(idf: IDF):
|
|
58
|
+
airboundaries =idf.idfobjects["CONSTRUCTION:AIRBOUNDARY"]
|
|
59
|
+
for ab in airboundaries:
|
|
60
|
+
wall = get_surface_by_name(idf, get_airboundary_wall(ab))
|
|
61
|
+
assert wall
|
|
62
|
+
partner_wall = get_partner_of_surface(idf, wall)
|
|
63
|
+
assert partner_wall
|
|
64
|
+
|
|
65
|
+
afn_zone_names = get_afn_zones(idf)
|
|
66
|
+
if wall.Zone_Name not in afn_zone_names:
|
|
67
|
+
print(f"{wall.Zone_Name} not in original AFN. Adding now.. " )
|
|
68
|
+
idf = add_zone(idf, wall.Zone_Name)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
afn_zone_names = get_afn_zones(idf)
|
|
72
|
+
if partner_wall.Zone_Name not in afn_zone_names:
|
|
73
|
+
print(f"Partner {partner_wall.Zone_Name} not in original AFN. Adding now.. " )
|
|
74
|
+
idf = add_zone(idf, partner_wall.Zone_Name)
|
|
75
|
+
|
|
76
|
+
return idf
|
|
77
|
+
|
|
78
|
+
def add_missing_zone_surfaces(idf: IDF, zone: str):
|
|
79
|
+
zone_subsurfs = find_zone_subsurfaces(zone, idf.getsubsurfaces())
|
|
80
|
+
afn_surfaces = [i.Surface_Name for i in idf.idfobjects["AIRFLOWNETWORK:MULTIZONE:SURFACE"]]
|
|
81
|
+
for subsurf in zone_subsurfs:
|
|
82
|
+
if subsurf not in afn_surfaces and PARTNER not in subsurf and "Window" in subsurf:
|
|
83
|
+
print(f"Subsurf {subsurf} not in original AFN. Adding now.. " )
|
|
84
|
+
idf = add_subsurface(idf, subsurf)
|
|
85
|
+
return idf
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def update_afn_for_missing_zone_subsurfaces(idf: IDF):
|
|
89
|
+
afn_zones = get_afn_zones(idf)
|
|
90
|
+
for zone in afn_zones:
|
|
91
|
+
idf = add_missing_zone_surfaces(idf, zone)
|
|
92
|
+
|
|
93
|
+
return idf
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# TODO now have added zones, need to update create zone map based on airboundaries.. and look for
|
|
97
|
+
|
|
98
|
+
def add_air_boundaries(idf: IDF, path_to_inputs: Path):
|
|
99
|
+
idf = update_air_boundary_constructions(idf, path_to_inputs)
|
|
100
|
+
idf = update_afn_for_airboundary_zones(idf)
|
|
101
|
+
idf = update_afn_for_missing_zone_subsurfaces(idf)
|
|
102
|
+
|
|
103
|
+
return idf
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from airflow_network.logic import get_afn_zones_and_subsurfaces
|
|
2
|
+
from airflow_network.modifiers import add_simulation_control, add_subsurface, add_zone
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
from geomeppy import IDF
|
|
6
|
+
from copy import deepcopy
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def add_airflownetwork_to_case(_idf: IDF):
|
|
10
|
+
idf = deepcopy(_idf)
|
|
11
|
+
zones, subsurfaces = get_afn_zones_and_subsurfaces(idf)
|
|
12
|
+
|
|
13
|
+
idf = add_simulation_control(idf)
|
|
14
|
+
|
|
15
|
+
for zone in zones:
|
|
16
|
+
idf = add_zone(idf, zone)
|
|
17
|
+
|
|
18
|
+
for subsurface in subsurfaces:
|
|
19
|
+
idf = add_subsurface(idf, subsurface)
|
|
20
|
+
|
|
21
|
+
return idf
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from geomeppy import IDF
|
|
2
|
+
from helpers.helpers import set_difference, list_all_dict_values
|
|
3
|
+
from helpers.ep_helpers import create_zone_map_without_partners
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def get_afn_zones_and_subsurfaces(idf: IDF):
|
|
7
|
+
# TODO make this more expressive, so know from function name it is mapping subsurfaces to zones..
|
|
8
|
+
zone_map = create_zone_map_without_partners(idf)
|
|
9
|
+
filtered_zone_map = {k: v for k, v in zone_map.items() if len(v) < 2}
|
|
10
|
+
afn_zones = set_difference(zone_map.keys(), filtered_zone_map.keys())
|
|
11
|
+
afn_subsurfaces = set_difference(
|
|
12
|
+
list_all_dict_values(zone_map), list_all_dict_values(filtered_zone_map)
|
|
13
|
+
)
|
|
14
|
+
return afn_zones, afn_subsurfaces
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from copy import deepcopy
|
|
2
|
+
from geomeppy import IDF
|
|
3
|
+
|
|
4
|
+
def add_simulation_control(idf: IDF):
|
|
5
|
+
sim_control = idf.newidfobject(
|
|
6
|
+
"AirflowNetwork:SimulationControl".upper()
|
|
7
|
+
)
|
|
8
|
+
sim_control.Name = "AFN_SIM_CONTROL"
|
|
9
|
+
sim_control.AirflowNetwork_Control = "MultizoneWithoutDistribution"
|
|
10
|
+
return idf
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def add_zone(idf: IDF, zone_name:str):
|
|
14
|
+
zone = idf.newidfobject(
|
|
15
|
+
"AirflowNetwork:MultiZone:Zone".upper()
|
|
16
|
+
)
|
|
17
|
+
zone.Ventilation_Control_Mode = "Constant"
|
|
18
|
+
zone.Zone_Name = zone_name
|
|
19
|
+
return idf
|
|
20
|
+
|
|
21
|
+
def create_simple_opening(idf: IDF, subsurface_name:str):
|
|
22
|
+
opening = idf.newidfobject(
|
|
23
|
+
"AirflowNetwork:MultiZone:Component:SimpleOpening".upper()
|
|
24
|
+
)
|
|
25
|
+
opening.Name = f"{subsurface_name} SimpleOpening"
|
|
26
|
+
# taken from defaults
|
|
27
|
+
opening.Discharge_Coefficient = 1
|
|
28
|
+
opening.Air_Mass_Flow_Coefficient_When_Opening_is_Closed = 0.001
|
|
29
|
+
opening.Minimum_Density_Difference_for_TwoWay_Flow = 0.0001
|
|
30
|
+
return idf, opening
|
|
31
|
+
|
|
32
|
+
def add_subsurface(idf: IDF, subsurface_name:str):
|
|
33
|
+
afn_surface = idf.newidfobject(
|
|
34
|
+
"AirflowNetwork:MultiZone:Surface".upper()
|
|
35
|
+
)
|
|
36
|
+
afn_surface.Surface_Name = subsurface_name
|
|
37
|
+
|
|
38
|
+
idf, opening = create_simple_opening(idf, subsurface_name)
|
|
39
|
+
afn_surface.Leakage_Component_Name = opening.Name
|
|
40
|
+
return idf
|
|
41
|
+
|
|
42
|
+
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from helpers.variable_interfaces import all_variables
|
|
2
|
+
from setup.data_wrangle import create_dataframe_for_many_cases, join_any_data
|
|
3
|
+
from setup.interfaces import CaseData
|
|
4
|
+
from setup.setup import retrieve_case_data
|
|
5
|
+
import polars as pl
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_qois():
|
|
9
|
+
qoi1 = all_variables.afn.linkage["flow12"]
|
|
10
|
+
qoi12 = all_variables.afn.linkage["flow21"]
|
|
11
|
+
qoi2 = all_variables.afn.zone["ach"]
|
|
12
|
+
qoi3 = all_variables.afn.zone["vent_vol"]
|
|
13
|
+
qoi4 = all_variables.zone.temp["zone_mean_air_temp"]
|
|
14
|
+
|
|
15
|
+
return qoi1, qoi12, qoi2, qoi3, qoi4
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_df(case_data: CaseData):
|
|
19
|
+
qois = get_qois()
|
|
20
|
+
df = create_dataframe_for_many_cases([case_data], qois[0])
|
|
21
|
+
return join_any_data(df, [case_data], qois[1])
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_zone_df(case_data: CaseData):
|
|
25
|
+
_, _, ach, vent_vol , *_= get_qois()
|
|
26
|
+
df = create_dataframe_for_many_cases([case_data], ach)
|
|
27
|
+
return join_any_data(df, [case_data], vent_vol)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_airboundary_case():
|
|
31
|
+
inputs_dir = "case_bol_5"
|
|
32
|
+
outputs_dir = "tests/test23_airwall"
|
|
33
|
+
return retrieve_case_data(inputs_dir, outputs_dir, "airwall")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_airboundary_with_surf_case():
|
|
37
|
+
inputs_dir = "case_bol_5"
|
|
38
|
+
outputs_dir = "tests/test25_airwall"
|
|
39
|
+
return retrieve_case_data(inputs_dir, outputs_dir, "airwall_surf")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def get_no_door_case():
|
|
43
|
+
inputs_dir = "case_bol_5"
|
|
44
|
+
outputs_dir = "tests/test24_no_door"
|
|
45
|
+
return retrieve_case_data(inputs_dir, outputs_dir, "no_door")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def get_normal_door_case():
|
|
49
|
+
inputs_dir = "case_bol_5"
|
|
50
|
+
outputs_dir = "oct_h4h_plans/case_bol_5"
|
|
51
|
+
return retrieve_case_data(inputs_dir, outputs_dir, "just_door")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def create_data(df_select):
|
|
55
|
+
dfs = [
|
|
56
|
+
df_select(i)
|
|
57
|
+
for i in [
|
|
58
|
+
get_no_door_case(),
|
|
59
|
+
get_airboundary_case(),
|
|
60
|
+
get_airboundary_with_surf_case(),
|
|
61
|
+
get_normal_door_case(),
|
|
62
|
+
]
|
|
63
|
+
]
|
|
64
|
+
return pl.concat(dfs, how="vertical")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def get_df_many(case_data: list[CaseData]):
|
|
68
|
+
qois = get_qois()
|
|
69
|
+
df = create_dataframe_for_many_cases(case_data, qois[0])
|
|
70
|
+
return join_any_data(df, case_data, qois[1])
|
|
71
|
+
|
|
72
|
+
def get_zone_df_many(case_data: list[CaseData]):
|
|
73
|
+
_, _, ach, vent_vol , temp = get_qois()
|
|
74
|
+
df = create_dataframe_for_many_cases(case_data, temp)
|
|
75
|
+
return join_any_data(df, case_data, ach)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from math import log, sin, cos, pow, radians
|
|
2
|
+
|
|
3
|
+
# TO DO, read this paper, how did they fit this?
|
|
4
|
+
# inc_rad => indident angle in radians, ~ angle between wind direction and and outward normal of wall under consideration..
|
|
5
|
+
# side_ratio_fac => log(width of facade / width of adjacent facade)
|
|
6
|
+
def calc_cp(inc_angle, side_ratio_fac=log(1)):
|
|
7
|
+
# TODO check that side_ratio_fac falls within bounds..
|
|
8
|
+
inc_rad = radians(inc_angle)
|
|
9
|
+
cos_inc_rad_over_2 = cos(inc_rad / 2)
|
|
10
|
+
val = 0.6 * log(
|
|
11
|
+
1.248
|
|
12
|
+
- 0.703 * sin(inc_rad / 2.0)
|
|
13
|
+
- 1.175 * pow(sin(inc_rad), 2)
|
|
14
|
+
+ 0.131 * pow(sin(2.0 * inc_rad * side_ratio_fac), 3)
|
|
15
|
+
+ 0.769 * cos_inc_rad_over_2
|
|
16
|
+
+ 0.07 * pow((side_ratio_fac * sin(inc_rad / 2.0)), 2)
|
|
17
|
+
+ 0.717 * pow(cos_inc_rad_over_2, 2)
|
|
18
|
+
)
|
|
19
|
+
return val
|
|
20
|
+
|
|
21
|
+
# side ratios are capped at a certain value..
|
|
22
|
+
# how does Cp become pressure?
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import polars as pl
|
|
2
|
+
from analysis.helpers import (
|
|
3
|
+
extract_times,
|
|
4
|
+
link_dfs_for_qois,
|
|
5
|
+
map_linkage_names_to_G,
|
|
6
|
+
map_zone_names,
|
|
7
|
+
)
|
|
8
|
+
from setup.interfaces import CaseData
|
|
9
|
+
from helpers.variable_interfaces import all_variables
|
|
10
|
+
from setup.data_wrangle import (
|
|
11
|
+
create_dataframe_for_many_cases,
|
|
12
|
+
join_any_data,
|
|
13
|
+
create_dataframe_for_case,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def create_zone_vol_df_many(case_data: list[CaseData]):
|
|
18
|
+
vent_vol = all_variables.afn.zone["vent_vol"]
|
|
19
|
+
mix_vol = all_variables.afn.zone["mix_vol"]
|
|
20
|
+
temp = all_variables.zone.temp["zone_mean_air_temp"]
|
|
21
|
+
|
|
22
|
+
df = create_dataframe_for_many_cases(case_data, vent_vol)
|
|
23
|
+
df2 = join_any_data(df, case_data, mix_vol)
|
|
24
|
+
return join_any_data(df2, case_data, temp, 1)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def create_zone_rate_df(case: CaseData):
|
|
28
|
+
zq = all_variables.afn.zone
|
|
29
|
+
qois = [
|
|
30
|
+
zq["vent_heat_gain"],
|
|
31
|
+
zq["vent_heat_loss"],
|
|
32
|
+
zq["mix_heat_gain"],
|
|
33
|
+
zq["mix_heat_loss"],
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
dfs = [create_dataframe_for_case(case.case_name, case.sql, qoi) for qoi in qois]
|
|
37
|
+
return pl.concat(dfs, how="vertical")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def create_site_df(case: CaseData):
|
|
41
|
+
sq = all_variables.site
|
|
42
|
+
qois = [
|
|
43
|
+
sq.temp["db"],
|
|
44
|
+
sq.solar["direct_rad"],
|
|
45
|
+
sq.wind["speed"],
|
|
46
|
+
sq.wind["direction"],
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
dfs = [create_dataframe_for_case(case.case_name, case.sql, qoi) for qoi in qois]
|
|
50
|
+
return pl.concat(dfs, how="vertical")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
### above are df helpers.. ^
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def create_pressure_df(case: CaseData):
|
|
64
|
+
av = all_variables.afn
|
|
65
|
+
qois = [av.node["total_pressure"], av.node["wind_pressure"], av.node["temp"]]
|
|
66
|
+
|
|
67
|
+
df = link_dfs_for_qois(case, qois)
|
|
68
|
+
df = extract_times(df)
|
|
69
|
+
df = map_zone_names(case.path_to_input, df)
|
|
70
|
+
df = df.with_columns(
|
|
71
|
+
is_ext=pl.when(pl.col("room_names").str.contains("ExtNode"))
|
|
72
|
+
.then(True)
|
|
73
|
+
.otherwise(False)
|
|
74
|
+
)
|
|
75
|
+
return df
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def create_linkage_df(case: CaseData) -> pl.DataFrame:
|
|
79
|
+
av = all_variables.afn
|
|
80
|
+
qois = [
|
|
81
|
+
av.linkage["flow12"],
|
|
82
|
+
av.linkage["flow21"],
|
|
83
|
+
]
|
|
84
|
+
df = create_dataframe_for_case(case.case_name, case.sql, qois[0])
|
|
85
|
+
df = join_any_data(df, [case], qois[1])
|
|
86
|
+
df = df.with_columns(net_linkage=pl.col("values") - pl.col("values_0"))
|
|
87
|
+
|
|
88
|
+
df = map_linkage_names_to_G(case.idf, case.path_to_input, df)
|
|
89
|
+
|
|
90
|
+
def flip_edge(e):
|
|
91
|
+
return [e[1], e[0]]
|
|
92
|
+
|
|
93
|
+
flipped_edges = [
|
|
94
|
+
flip_edge(e) if v < 0 else e
|
|
95
|
+
for e, v in zip(df["room_pairs"], df["net_linkage"])
|
|
96
|
+
]
|
|
97
|
+
df = df.hstack([pl.Series("directed_pairs", flipped_edges)])
|
|
98
|
+
# )
|
|
99
|
+
return df
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import polars as pl
|
|
2
|
+
import polars.selectors as cs
|
|
3
|
+
from setup.interfaces import CaseData
|
|
4
|
+
from setup.materials_setup import retrieve_cases
|
|
5
|
+
from setup.data_wrangle2 import create_wide_dataframe_for_many_qois, add_site_qois_wide
|
|
6
|
+
from analysis.helpers import map_zone_names, extract_times, map_linkage_names_to_G
|
|
7
|
+
from helpers.variable_interfaces import all_variables as vars
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_redwood_case():
|
|
11
|
+
cases = retrieve_cases()
|
|
12
|
+
medium_cases = [i for i in cases if "Medium" in i.case_name]
|
|
13
|
+
[case] = [i for i in medium_cases if "red" in i.case_name]
|
|
14
|
+
return case
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# # TODO zone temp data..
|
|
18
|
+
# def get_col_regex(name):
|
|
19
|
+
# return pl.col(f"^{name}.*$")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def create_linkage_df(case: CaseData) -> pl.DataFrame:
|
|
23
|
+
av = vars.afn
|
|
24
|
+
qois = [
|
|
25
|
+
av.linkage["flow12"],
|
|
26
|
+
av.linkage["flow21"],
|
|
27
|
+
]
|
|
28
|
+
df = create_wide_dataframe_for_many_qois(case, qois)
|
|
29
|
+
df = df.with_columns(net_linkage=(cs.contains(qois[0]) - cs.contains(qois[1]))) # TODO check this calculation may be wrong
|
|
30
|
+
|
|
31
|
+
df = map_linkage_names_to_G(case.idf, case.path_to_input, df)
|
|
32
|
+
|
|
33
|
+
def flip_edge(e):
|
|
34
|
+
return [e[1], e[0]]
|
|
35
|
+
|
|
36
|
+
directed_pairs = [
|
|
37
|
+
flip_edge(e) if v < 0 else e
|
|
38
|
+
for e, v in zip(df["room_pairs"], df["net_linkage"])
|
|
39
|
+
]
|
|
40
|
+
df = df.hstack([pl.Series("directed_pairs", directed_pairs)])
|
|
41
|
+
return df
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_external_node_df(case: CaseData):
|
|
45
|
+
df = create_wide_dataframe_for_many_qois(case, [vars.afn.node["wind_pressure"]])
|
|
46
|
+
return add_site_qois_wide(df, case, [vars.site.wind["speed"], vars.site.wind["direction"]])
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# def create_vol_df_for_many_cases():
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// SUBROUTINE LOCAL VARIABLE DECLARATIONS:
|
|
2
|
+
int FacadeNum; // Facade number
|
|
3
|
+
int ExtNum; // External number
|
|
4
|
+
int AFNZnNum; // Zone number
|
|
5
|
+
Real64 SideRatio; // For vertical facades, width of facade / width of adjacent facade
|
|
6
|
+
Real64 SR; // SideRatio restricted to 0.25 to 4.0 range
|
|
7
|
+
Real64 SideRatioFac; // LOG(SideRatio)
|
|
8
|
+
Real64 IncRad; // IncAng in radians
|
|
9
|
+
int IAng; // Incidence angle index; used in interpolation
|
|
10
|
+
Real64 DelAng; // Incidence angle difference; used in interpolation
|
|
11
|
+
Real64 WtAng; // Incidence angle weighting factor; used in interpolation
|
|
12
|
+
int ISR; // Side ratio index, for interpolation
|
|
13
|
+
Real64 WtSR; // Side ratio weighting factor; used in interpolation
|
|
14
|
+
int SurfNum; // Surface number
|
|
15
|
+
int SurfDatNum; // Surface data number
|
|
16
|
+
Real64 SurfAng; // Azimuth angle of surface normal (degrees clockwise from North)
|
|
17
|
+
int FacadeNumThisSurf; // Facade number for a particular surface
|
|
18
|
+
Real64 AngDiff; // Angle difference between wind and surface direction (deg)
|
|
19
|
+
Real64 AngDiffMin; // Minimum angle difference between wind and surface direction (deg)
|
|
20
|
+
std::vector<int> curveIndex = {0, 0, 0, 0, 0};
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
std::vector<Real64> vals(13);
|
|
25
|
+
for (int windDirNum = 1; windDirNum <= 12; ++windDirNum) {
|
|
26
|
+
Real64 WindAng = (windDirNum - 1) * 30.0;
|
|
27
|
+
IncAng = std::abs(WindAng - FacadeAng(FacadeNum));
|
|
28
|
+
if (IncAng > 180.0) IncAng = 360.0 - IncAng;
|
|
29
|
+
IAng = int(IncAng / 30.0) + 1;
|
|
30
|
+
DelAng = mod(IncAng, 30.0);
|
|
31
|
+
WtAng = 1.0 - DelAng / 30.0;
|
|
32
|
+
|
|
33
|
+
// Wind-pressure coefficients for vertical facades, low-rise building
|
|
34
|
+
|
|
35
|
+
if (Util::SameString(simulation_control.BldgType, "LowRise") && FacadeNum <= 4) {
|
|
36
|
+
IncRad = IncAng * Constant::DegToRadians;
|
|
37
|
+
Real64 const cos_IncRad_over_2(std::cos(IncRad / 2.0));
|
|
38
|
+
vals[windDirNum - 1] = 0.6 * std::log(1.248 - 0.703 * std::sin(IncRad / 2.0) - 1.175 * pow_2(std::sin(IncRad)) +
|
|
39
|
+
0.131 * pow_3(std::sin(2.0 * IncRad * SideRatioFac)) + 0.769 * cos_IncRad_over_2 +
|
|
40
|
+
0.07 * pow_2(SideRatioFac * std::sin(IncRad / 2.0)) + 0.717 * pow_2(cos_IncRad_over_2));
|
|
41
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from geomeppy import IDF
|
|
3
|
+
import polars as pl
|
|
4
|
+
from helpers.ep_helpers import get_zone_num
|
|
5
|
+
from sklearn.preprocessing import MinMaxScaler
|
|
6
|
+
import numpy as np
|
|
7
|
+
from helpers.geometry_interfaces import Domain
|
|
8
|
+
from network.network import create_base_graph, get_node_partners
|
|
9
|
+
from plan.helpers import create_room_map
|
|
10
|
+
from setup.data_wrangle import create_dataframe_for_case
|
|
11
|
+
from setup.interfaces import CaseData
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_domains_lim(zone_domains: list[Domain], PAD_BASE = 1.4):
|
|
15
|
+
PAD = PAD_BASE * 1.1
|
|
16
|
+
min_x = min([i.width.min for i in zone_domains]) - PAD
|
|
17
|
+
max_x = max([i.width.max for i in zone_domains]) + PAD
|
|
18
|
+
min_y = min([i.height.min for i in zone_domains]) - PAD
|
|
19
|
+
max_y = max([i.height.max for i in zone_domains]) + PAD
|
|
20
|
+
return (min_x, max_x), (min_y, max_y)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_min_max(medians: pl.DataFrame, col=None):
|
|
24
|
+
if not col:
|
|
25
|
+
numeric_values = medians.select(pl.selectors.numeric())
|
|
26
|
+
min_val = numeric_values.min_horizontal().min()
|
|
27
|
+
max_val = numeric_values.max_horizontal().max()
|
|
28
|
+
|
|
29
|
+
else:
|
|
30
|
+
series = medians[col]
|
|
31
|
+
return series.min(), series.max()
|
|
32
|
+
|
|
33
|
+
return min_val, max_val
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def true_min_max(min_max_pairs: list[tuple[float, float]]):
|
|
37
|
+
min_val = min([m[0] for m in min_max_pairs])
|
|
38
|
+
max_val = max([m[1] for m in min_max_pairs])
|
|
39
|
+
return min_val, max_val
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def convert_zone_space_name(room_map: dict[int, str], name):
|
|
43
|
+
try:
|
|
44
|
+
ix = get_zone_num(name)
|
|
45
|
+
room_name = room_map[ix]
|
|
46
|
+
return f"{ix}-{room_name}"
|
|
47
|
+
except:
|
|
48
|
+
return name
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def normalize_column(df: pl.DataFrame, col: str, range=(1, 3)):
|
|
52
|
+
vals = np.absolute(df[col].to_numpy().reshape(-1, 1))
|
|
53
|
+
scaler = MinMaxScaler(feature_range=range)
|
|
54
|
+
scaler.fit(vals)
|
|
55
|
+
return scaler.transform(vals).reshape(1, -1)[0]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def link_dfs_for_qois(case: CaseData, qois: list[str]):
|
|
59
|
+
df = [create_dataframe_for_case(case.case_name, case.sql, qoi) for qoi in qois]
|
|
60
|
+
return pl.concat(df, how="vertical")
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def map_zone_names(path_to_input: Path, df: pl.DataFrame):
|
|
64
|
+
room_map = create_room_map(path_to_input)
|
|
65
|
+
fx = lambda name: convert_zone_space_name(room_map, name)
|
|
66
|
+
return df.with_columns(
|
|
67
|
+
room_names=pl.col("space_names").map_elements(fx, return_dtype=pl.String),
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def map_linkage_names_to_G(idf: IDF, path_to_input: Path, df: pl.DataFrame):
|
|
72
|
+
G, _ = create_base_graph(idf, path_to_input)
|
|
73
|
+
fx = lambda surf_name: get_node_partners(idf, G, surf_name)
|
|
74
|
+
return df.with_columns(
|
|
75
|
+
room_pairs=pl.col("space_names").map_elements(fx, return_dtype=pl.Object)
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def extract_times(df: pl.DataFrame):
|
|
80
|
+
return df.with_columns(time=pl.col("datetimes").dt.to_string("%H:%M"))
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import seaborn as sns
|
|
3
|
+
import seaborn.objects as so
|
|
4
|
+
import polars as pl
|
|
5
|
+
import numpy as np
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
|
|
8
|
+
from analysis.volumes import aggregate_and_compare
|
|
9
|
+
from setup.data_wrangle import get_plot_labels
|
|
10
|
+
|
|
11
|
+
# from setup.materials_setup import *
|
|
12
|
+
from analysis.dataframes import create_zone_vol_df_many
|
|
13
|
+
from setup.interfaces import CaseData
|
|
14
|
+
from setup.materials_setup import retrieve_cases
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_save_details():
|
|
18
|
+
FOLDER = "materials_compare"
|
|
19
|
+
return Path.cwd() / "figures" / FOLDER
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def init_df():
|
|
23
|
+
cases = retrieve_cases()
|
|
24
|
+
df_vol = create_zone_vol_df_many(cases)
|
|
25
|
+
sc = cases[0]
|
|
26
|
+
return df_vol, sc
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def aggregate_and_compare_materials(df_vol):
|
|
30
|
+
figures_root = get_save_details()
|
|
31
|
+
df_agg = aggregate_and_compare(df_vol)
|
|
32
|
+
df_agg2 = df_agg.with_columns(
|
|
33
|
+
material_type=pl.when(pl.col("case_names").str.contains("Light"))
|
|
34
|
+
.then(pl.lit("Light"))
|
|
35
|
+
.when(pl.col("case_names").str.contains("Medium"))
|
|
36
|
+
.then(pl.lit("Medium"))
|
|
37
|
+
.otherwise(pl.lit("Heavy")),
|
|
38
|
+
case_type = pl.when(pl.col("case_names").str.contains("amb"))
|
|
39
|
+
.then(pl.lit("amb"))
|
|
40
|
+
.when(pl.col("case_names").str.contains("bol"))
|
|
41
|
+
.then(pl.lit("bol"))
|
|
42
|
+
.otherwise(pl.lit("red")),
|
|
43
|
+
)
|
|
44
|
+
g = (so.Plot(df_agg2, x="temp", y="combined_vent", color="case_type", marker="material_type" ).add(so.Dot(pointsize=15)).scale(color="flare").plot().save(figures_root / f"vent_v_temp")) # type: ignore
|
|
45
|
+
g.show()
|
|
46
|
+
return df_agg2, g
|
|
47
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
from case_edits.epcase import EneryPlusCaseEditor
|
|
3
|
+
from case_edits.ezcase import get_path_to_inputs, get_path_to_outputs
|
|
4
|
+
from experiments.comparisons import get_input_dir
|
|
5
|
+
from helpers.ep_geom_helpers import get_zone_domains
|
|
6
|
+
from analysis.helpers import get_domains_lim
|
|
7
|
+
from helpers.geometry_interfaces import Range, Domain
|
|
8
|
+
from plan.plan_to_eppy import add_eppy_blocks_to_case
|
|
9
|
+
from setup.setup import get_case_names
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
output_path = get_path_to_outputs("test/plan_details")
|
|
13
|
+
|
|
14
|
+
def get_input_paths():
|
|
15
|
+
input_dirs = [get_input_dir(i) for i in get_case_names()]
|
|
16
|
+
return [get_path_to_inputs(i) for i in input_dirs]
|
|
17
|
+
|
|
18
|
+
def init_case(input_path):
|
|
19
|
+
case = EneryPlusCaseEditor(output_path)
|
|
20
|
+
case.idf = add_eppy_blocks_to_case(case.idf, input_path)
|
|
21
|
+
return get_zone_domains(case.idf)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_plan_area(zone_domains:list[Domain]):
|
|
25
|
+
return sum([z.area for z in zone_domains])
|
|
26
|
+
|
|
27
|
+
def get_plan_aspect_ratio(zone_domains:list[Domain]):
|
|
28
|
+
x_diff, y_diff = get_domains_lim(zone_domains, 0)
|
|
29
|
+
plan_domain = Domain(Range(*x_diff), Range(*y_diff))
|
|
30
|
+
return plan_domain.aspect_ratio
|
|
31
|
+
|