Spaces:
Sleeping
Sleeping
Update app/components.py
Browse files- app/components.py +53 -29
app/components.py
CHANGED
|
@@ -94,6 +94,14 @@ def migrate_component_types():
|
|
| 94 |
if comp_type != "floors" and "tilt" in component:
|
| 95 |
component["surface_tilt"] = component.pop("tilt")
|
| 96 |
logger.info(f"Renamed 'tilt' to 'surface_tilt' for component '{component['name']}'")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
|
| 98 |
def display_component_tab(comp_type: str):
|
| 99 |
"""
|
|
@@ -203,16 +211,19 @@ def display_component_tab(comp_type: str):
|
|
| 203 |
help="Tilt angle of the component relative to horizontal (0° = horizontal, 90° = vertical)."
|
| 204 |
)
|
| 205 |
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
"
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
|
|
|
|
|
|
|
|
|
| 216 |
)
|
| 217 |
|
| 218 |
# Construction or fenestration selection
|
|
@@ -330,8 +341,9 @@ def display_component_tab(comp_type: str):
|
|
| 330 |
component_data["surface_azimuth"] = surface_azimuth
|
| 331 |
component_data["surface_tilt"] = surface_tilt
|
| 332 |
|
| 333 |
-
if comp_type
|
| 334 |
-
component_data["
|
|
|
|
| 335 |
|
| 336 |
if comp_type in ["walls", "roofs", "floors"]:
|
| 337 |
component_data["construction"] = construction
|
|
@@ -390,15 +402,17 @@ def display_component_tab(comp_type: str):
|
|
| 390 |
def display_wall_window_table(comp_type: str, components: List[Dict[str, Any]]):
|
| 391 |
"""Display a table of walls or windows with appropriate columns."""
|
| 392 |
# Create column headers
|
| 393 |
-
cols = st.columns([2, 1, 1, 1, 1, 1, 1] if comp_type == "walls" else [2, 1, 1, 1, 1, 1, 1, 1])
|
| 394 |
cols[0].write("**Name**")
|
| 395 |
cols[1].write("**U-Value**")
|
| 396 |
cols[2].write("**Area (m²)**")
|
| 397 |
cols[3].write("**Surface Azimuth (°)**")
|
| 398 |
cols[4].write("**Surface Tilt (°)**")
|
| 399 |
if comp_type == "walls":
|
| 400 |
-
cols[5].write("**
|
| 401 |
-
cols[6].write("**
|
|
|
|
|
|
|
| 402 |
else: # windows
|
| 403 |
cols[5].write("**SC**")
|
| 404 |
cols[6].write("**Edit**")
|
|
@@ -406,18 +420,19 @@ def display_wall_window_table(comp_type: str, components: List[Dict[str, Any]]):
|
|
| 406 |
|
| 407 |
# Display each component
|
| 408 |
for idx, comp in enumerate(components):
|
| 409 |
-
cols = st.columns([2, 1, 1, 1, 1, 1, 1] if comp_type == "walls" else [2, 1, 1, 1, 1, 1, 1, 1])
|
| 410 |
cols[0].write(comp["name"])
|
| 411 |
cols[1].write(f"{comp.get('u_value', 0.0):.3f}")
|
| 412 |
cols[2].write(f"{comp['area']:.2f}")
|
| 413 |
cols[3].write(f"{comp.get('surface_azimuth', 0.0):.0f}")
|
| 414 |
cols[4].write(f"{comp.get('surface_tilt', 90.0):.0f}")
|
| 415 |
-
if comp_type == "
|
| 416 |
-
cols[5].write(
|
|
|
|
| 417 |
|
| 418 |
# Edit button
|
| 419 |
edit_key = f"edit_{comp_type}_{comp['name']}_{idx}"
|
| 420 |
-
edit_col =
|
| 421 |
with cols[edit_col].container():
|
| 422 |
if st.button("Edit", key=edit_key):
|
| 423 |
editor_data = {
|
|
@@ -432,6 +447,8 @@ def display_wall_window_table(comp_type: str, components: List[Dict[str, Any]]):
|
|
| 432 |
|
| 433 |
if comp_type == "walls":
|
| 434 |
editor_data["construction"] = comp.get("construction", "")
|
|
|
|
|
|
|
| 435 |
else: # windows
|
| 436 |
editor_data["fenestration"] = comp.get("fenestration", "")
|
| 437 |
editor_data["parent_component"] = comp.get("parent_component", "")
|
|
@@ -444,7 +461,7 @@ def display_wall_window_table(comp_type: str, components: List[Dict[str, Any]]):
|
|
| 444 |
|
| 445 |
# Delete button
|
| 446 |
delete_key = f"delete_{comp_type}_{comp['name']}_{idx}"
|
| 447 |
-
delete_col =
|
| 448 |
with cols[delete_col].container():
|
| 449 |
if st.button("Delete", key=delete_key):
|
| 450 |
st.session_state.project_data["components"][comp_type].pop(idx)
|
|
@@ -520,32 +537,35 @@ def display_roof_skylight_table(comp_type: str, components: List[Dict[str, Any]]
|
|
| 520 |
def display_floor_table(comp_type: str, components: List[Dict[str, Any]]):
|
| 521 |
"""Display a table of floors with appropriate columns."""
|
| 522 |
# Create column headers
|
| 523 |
-
cols = st.columns([2, 1, 1, 1, 1, 1])
|
| 524 |
cols[0].write("**Name**")
|
| 525 |
cols[1].write("**U-Value**")
|
| 526 |
cols[2].write("**Area (m²)**")
|
| 527 |
-
cols[3].write("**
|
| 528 |
-
cols[4].write("**
|
| 529 |
-
cols[5].write("**
|
|
|
|
| 530 |
|
| 531 |
# Display each component
|
| 532 |
for idx, comp in enumerate(components):
|
| 533 |
-
cols = st.columns([2, 1, 1, 1, 1, 1])
|
| 534 |
cols[0].write(comp["name"])
|
| 535 |
cols[1].write(f"{comp.get('u_value', 0.0):.3f}")
|
| 536 |
cols[2].write(f"{comp['area']:.2f}")
|
| 537 |
-
cols[3].write(
|
|
|
|
| 538 |
|
| 539 |
# Edit button
|
| 540 |
edit_key = f"edit_{comp_type}_{comp['name']}_{idx}"
|
| 541 |
-
with cols[
|
| 542 |
if st.button("Edit", key=edit_key):
|
| 543 |
editor_data = {
|
| 544 |
"index": idx,
|
| 545 |
"name": comp["name"],
|
| 546 |
"area": comp["area"],
|
| 547 |
"construction": comp.get("construction", ""),
|
| 548 |
-
"
|
|
|
|
| 549 |
"is_edit": True
|
| 550 |
}
|
| 551 |
|
|
@@ -555,7 +575,7 @@ def display_floor_table(comp_type: str, components: List[Dict[str, Any]]):
|
|
| 555 |
|
| 556 |
# Delete button
|
| 557 |
delete_key = f"delete_{comp_type}_{comp['name']}_{idx}"
|
| 558 |
-
with cols[
|
| 559 |
if st.button("Delete", key=delete_key):
|
| 560 |
st.session_state.project_data["components"][comp_type].pop(idx)
|
| 561 |
st.success(f"{comp_type[:-1].capitalize()} '{comp['name']}' deleted!")
|
|
@@ -668,6 +688,8 @@ def display_components_help():
|
|
| 668 |
* **Surface Tilt**: Angle of the component relative to horizontal (0° = horizontal, 90° = vertical).
|
| 669 |
* **Parent Component**: The wall or roof that contains a window or skylight.
|
| 670 |
* **Shading Coefficient (SC)**: Factor for shading devices on windows/skylights (0.0 to 1.0).
|
|
|
|
|
|
|
| 671 |
|
| 672 |
**Workflow:**
|
| 673 |
|
|
@@ -681,4 +703,6 @@ def display_components_help():
|
|
| 681 |
* For roofs and skylights, set surface tilt to 0° for flat surfaces.
|
| 682 |
* Ensure the total area of windows doesn't exceed the area of their parent walls.
|
| 683 |
* Ensure the total area of skylights doesn't exceed the area of their parent roofs.
|
|
|
|
|
|
|
| 684 |
""")
|
|
|
|
| 94 |
if comp_type != "floors" and "tilt" in component:
|
| 95 |
component["surface_tilt"] = component.pop("tilt")
|
| 96 |
logger.info(f"Renamed 'tilt' to 'surface_tilt' for component '{component['name']}'")
|
| 97 |
+
# Add adiabatic and ground_contact if not present for walls and floors
|
| 98 |
+
if comp_type in ["walls", "floors"]:
|
| 99 |
+
if "adiabatic" not in component:
|
| 100 |
+
component["adiabatic"] = False
|
| 101 |
+
logger.info(f"Added 'adiabatic' to component '{component['name']}'")
|
| 102 |
+
if "ground_contact" not in component:
|
| 103 |
+
component["ground_contact"] = False
|
| 104 |
+
logger.info(f"Added 'ground_contact' to component '{component['name']}'")
|
| 105 |
|
| 106 |
def display_component_tab(comp_type: str):
|
| 107 |
"""
|
|
|
|
| 211 |
help="Tilt angle of the component relative to horizontal (0° = horizontal, 90° = vertical)."
|
| 212 |
)
|
| 213 |
|
| 214 |
+
# Adiabatic and Ground Contact for walls and floors
|
| 215 |
+
if comp_type in ["walls", "floors"]:
|
| 216 |
+
adiabatic = st.selectbox(
|
| 217 |
+
"Adiabatic",
|
| 218 |
+
["Yes", "No"],
|
| 219 |
+
index=0 if editor_state.get("adiabatic", False) else 1,
|
| 220 |
+
help="Select 'Yes' if the component is adiabatic (no heat transfer across it)."
|
| 221 |
+
)
|
| 222 |
+
ground_contact = st.selectbox(
|
| 223 |
+
"Ground Contact",
|
| 224 |
+
["Yes", "No"],
|
| 225 |
+
index=0 if editor_state.get("ground_contact", False) else 1,
|
| 226 |
+
help="Select 'Yes' if the component is in contact with the ground."
|
| 227 |
)
|
| 228 |
|
| 229 |
# Construction or fenestration selection
|
|
|
|
| 341 |
component_data["surface_azimuth"] = surface_azimuth
|
| 342 |
component_data["surface_tilt"] = surface_tilt
|
| 343 |
|
| 344 |
+
if comp_type in ["walls", "floors"]:
|
| 345 |
+
component_data["adiabatic"] = adiabatic == "Yes"
|
| 346 |
+
component_data["ground_contact"] = ground_contact == "Yes"
|
| 347 |
|
| 348 |
if comp_type in ["walls", "roofs", "floors"]:
|
| 349 |
component_data["construction"] = construction
|
|
|
|
| 402 |
def display_wall_window_table(comp_type: str, components: List[Dict[str, Any]]):
|
| 403 |
"""Display a table of walls or windows with appropriate columns."""
|
| 404 |
# Create column headers
|
| 405 |
+
cols = st.columns([2, 1, 1, 1, 1, 1, 1, 1, 1] if comp_type == "walls" else [2, 1, 1, 1, 1, 1, 1, 1])
|
| 406 |
cols[0].write("**Name**")
|
| 407 |
cols[1].write("**U-Value**")
|
| 408 |
cols[2].write("**Area (m²)**")
|
| 409 |
cols[3].write("**Surface Azimuth (°)**")
|
| 410 |
cols[4].write("**Surface Tilt (°)**")
|
| 411 |
if comp_type == "walls":
|
| 412 |
+
cols[5].write("**Adiabatic**")
|
| 413 |
+
cols[6].write("**Ground Contact**")
|
| 414 |
+
cols[7].write("**Edit**")
|
| 415 |
+
cols[8].write("**Delete**")
|
| 416 |
else: # windows
|
| 417 |
cols[5].write("**SC**")
|
| 418 |
cols[6].write("**Edit**")
|
|
|
|
| 420 |
|
| 421 |
# Display each component
|
| 422 |
for idx, comp in enumerate(components):
|
| 423 |
+
cols = st.columns([2, 1, 1, 1, 1, 1, 1, 1, 1] if comp_type == "walls" else [2, 1, 1, 1, 1, 1, 1, 1])
|
| 424 |
cols[0].write(comp["name"])
|
| 425 |
cols[1].write(f"{comp.get('u_value', 0.0):.3f}")
|
| 426 |
cols[2].write(f"{comp['area']:.2f}")
|
| 427 |
cols[3].write(f"{comp.get('surface_azimuth', 0.0):.0f}")
|
| 428 |
cols[4].write(f"{comp.get('surface_tilt', 90.0):.0f}")
|
| 429 |
+
if comp_type == "walls":
|
| 430 |
+
cols[5].write("Yes" if comp.get("adiabatic", False) else "No")
|
| 431 |
+
cols[6].write("Yes" if comp.get("ground_contact", False) else "No")
|
| 432 |
|
| 433 |
# Edit button
|
| 434 |
edit_key = f"edit_{comp_type}_{comp['name']}_{idx}"
|
| 435 |
+
edit_col = 7 if comp_type == "walls" else 6
|
| 436 |
with cols[edit_col].container():
|
| 437 |
if st.button("Edit", key=edit_key):
|
| 438 |
editor_data = {
|
|
|
|
| 447 |
|
| 448 |
if comp_type == "walls":
|
| 449 |
editor_data["construction"] = comp.get("construction", "")
|
| 450 |
+
editor_data["adiabatic"] = comp.get("adiabatic", False)
|
| 451 |
+
editor_data["ground_contact"] = comp.get("ground_contact", False)
|
| 452 |
else: # windows
|
| 453 |
editor_data["fenestration"] = comp.get("fenestration", "")
|
| 454 |
editor_data["parent_component"] = comp.get("parent_component", "")
|
|
|
|
| 461 |
|
| 462 |
# Delete button
|
| 463 |
delete_key = f"delete_{comp_type}_{comp['name']}_{idx}"
|
| 464 |
+
delete_col = 8 if comp_type == "walls" else 7
|
| 465 |
with cols[delete_col].container():
|
| 466 |
if st.button("Delete", key=delete_key):
|
| 467 |
st.session_state.project_data["components"][comp_type].pop(idx)
|
|
|
|
| 537 |
def display_floor_table(comp_type: str, components: List[Dict[str, Any]]):
|
| 538 |
"""Display a table of floors with appropriate columns."""
|
| 539 |
# Create column headers
|
| 540 |
+
cols = st.columns([2, 1, 1, 1, 1, 1, 1])
|
| 541 |
cols[0].write("**Name**")
|
| 542 |
cols[1].write("**U-Value**")
|
| 543 |
cols[2].write("**Area (m²)**")
|
| 544 |
+
cols[3].write("**Adiabatic**")
|
| 545 |
+
cols[4].write("**Ground Contact**")
|
| 546 |
+
cols[5].write("**Edit**")
|
| 547 |
+
cols[6].write("**Delete**")
|
| 548 |
|
| 549 |
# Display each component
|
| 550 |
for idx, comp in enumerate(components):
|
| 551 |
+
cols = st.columns([2, 1, 1, 1, 1, 1, 1])
|
| 552 |
cols[0].write(comp["name"])
|
| 553 |
cols[1].write(f"{comp.get('u_value', 0.0):.3f}")
|
| 554 |
cols[2].write(f"{comp['area']:.2f}")
|
| 555 |
+
cols[3].write("Yes" if comp.get("adiabatic", False) else "No")
|
| 556 |
+
cols[4].write("Yes" if comp.get("ground_contact", False) else "No")
|
| 557 |
|
| 558 |
# Edit button
|
| 559 |
edit_key = f"edit_{comp_type}_{comp['name']}_{idx}"
|
| 560 |
+
with cols[5].container():
|
| 561 |
if st.button("Edit", key=edit_key):
|
| 562 |
editor_data = {
|
| 563 |
"index": idx,
|
| 564 |
"name": comp["name"],
|
| 565 |
"area": comp["area"],
|
| 566 |
"construction": comp.get("construction", ""),
|
| 567 |
+
"adiabatic": comp.get("adiabatic", False),
|
| 568 |
+
"ground_contact": comp.get("ground_contact", False),
|
| 569 |
"is_edit": True
|
| 570 |
}
|
| 571 |
|
|
|
|
| 575 |
|
| 576 |
# Delete button
|
| 577 |
delete_key = f"delete_{comp_type}_{comp['name']}_{idx}"
|
| 578 |
+
with cols[6].container():
|
| 579 |
if st.button("Delete", key=delete_key):
|
| 580 |
st.session_state.project_data["components"][comp_type].pop(idx)
|
| 581 |
st.success(f"{comp_type[:-1].capitalize()} '{comp['name']}' deleted!")
|
|
|
|
| 688 |
* **Surface Tilt**: Angle of the component relative to horizontal (0° = horizontal, 90° = vertical).
|
| 689 |
* **Parent Component**: The wall or roof that contains a window or skylight.
|
| 690 |
* **Shading Coefficient (SC)**: Factor for shading devices on windows/skylights (0.0 to 1.0).
|
| 691 |
+
* **Adiabatic**: Indicates if a wall or floor has no heat transfer across it (Yes/No).
|
| 692 |
+
* **Ground Contact**: Indicates if a wall or floor is in contact with the ground (Yes/No).
|
| 693 |
|
| 694 |
**Workflow:**
|
| 695 |
|
|
|
|
| 703 |
* For roofs and skylights, set surface tilt to 0° for flat surfaces.
|
| 704 |
* Ensure the total area of windows doesn't exceed the area of their parent walls.
|
| 705 |
* Ensure the total area of skylights doesn't exceed the area of their parent roofs.
|
| 706 |
+
* Set adiabatic to 'Yes' for components with no heat transfer, such as internal partitions.
|
| 707 |
+
* Set ground contact to 'Yes' for components in direct contact with the ground for accurate heat transfer calculations.
|
| 708 |
""")
|