mabuseif commited on
Commit
a13e632
·
verified ·
1 Parent(s): b5dc343

Update app/construction.py

Browse files
Files changed (1) hide show
  1. app/construction.py +37 -67
app/construction.py CHANGED
@@ -20,15 +20,12 @@ from typing import Dict, List, Any, Optional, Tuple, Union
20
 
21
  # Import the centralized data module and materials library
22
  from app.m_c_data import get_default_constructions
23
- from app.materials_library import get_available_materials, Material
24
 
25
  # Configure logging
26
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
27
  logger = logging.getLogger(__name__)
28
 
29
- # Define constants
30
- CONSTRUCTION_TYPES = ["Wall", "Roof", "Floor"]
31
-
32
  # Surface resistances (EN ISO 6946 or ASHRAE)
33
  R_SI = 0.12 # Internal surface resistance (m²·K/W)
34
  R_SE = 0.04 # External surface resistance (m²·K/W)
@@ -42,10 +39,9 @@ class ConstructionLibrary:
42
  data = [
43
  {
44
  "Name": name,
45
- "Component Type": props["type"],
46
  "U-Value (W/m²·K)": props.get("u_value", 0.0),
47
  "R-Value (m²·K/W)": props.get("r_value", 0.0),
48
- "Thermal Mass (kJ/m²·K)": props.get("thermal_mass", 0.0),
49
  "Embodied Carbon (kgCO₂e/m²)": props.get("embodied_carbon", 0.0),
50
  "Cost (USD/m²)": props.get("cost", 0.0),
51
  "Layers": len(props.get("layers", []))
@@ -162,10 +158,7 @@ def display_construction_page():
162
  # Display project constructions DataFrame
163
  st.subheader("Project Constructions")
164
  try:
165
- construction_filter = st.session_state.get("construction_filter", "All")
166
  construction_df = construction_library.to_dataframe(st.session_state.project_data["constructions"]["project"])
167
- if construction_filter != "All":
168
- construction_df = construction_df[construction_df["Component Type"] == construction_filter]
169
  if not construction_df.empty:
170
  st.dataframe(construction_df, use_container_width=True)
171
  else:
@@ -199,43 +192,20 @@ def initialize_construction():
199
 
200
  def display_constructions_tables(construction_library: ConstructionLibrary):
201
  """Display library and project constructions tables."""
202
- # Component type filter
203
- filter_options = ["All"] + CONSTRUCTION_TYPES
204
- construction_filter = st.selectbox("Filter by Component Type", filter_options, key="construction_filter")
205
-
206
  st.subheader("Library Constructions")
207
  with st.container():
208
- library_constructions = list(construction_library.library_constructions.items()) # Changed to .items()
209
- if construction_filter != "All":
210
- library_constructions = [(name, c) for name, c in library_constructions if c["type"] == construction_filter]
211
- cols = st.columns([2, 1, 1, 1, 1])
212
  cols[0].write("**Name**")
213
- cols[1].write("**Thermal Mass**")
214
  cols[2].write("**U-Value (W/m²·K)**")
215
- cols[3].write("**Preview**")
216
- cols[4].write("**Copy**")
217
- for name, construction in library_constructions: # Changed to unpack name and construction
218
- cols = st.columns([2, 1, 1, 1, 1])
219
- cols[0].write(name) # Use name directly
220
- cols[1].write(f"{construction.get('thermal_mass', 0.0):.1f}")
221
  cols[2].write(f"{construction.get('u_value', 0.0):.3f}")
222
- if cols[3].button("Preview", key=f"preview_lib_cons_{name}"):
223
- if st.session_state.get("rerun_trigger") != f"preview_cons_{name}":
224
- st.session_state.rerun_trigger = f"preview_cons_{name}"
225
- st.session_state.construction_editor = {
226
- "name": name,
227
- "component_type": construction["type"],
228
- "layers": [{"material_name": layer["material"], "thickness": layer["thickness"]} for layer in construction["layers"]],
229
- "is_edit": False
230
- }
231
- st.session_state.construction_form_state = {
232
- "name": name,
233
- "component_type": construction["type"],
234
- "num_layers": len(construction["layers"]),
235
- "layers": [{"material_name": layer["material"], "thickness": layer["thickness"]} for layer in construction["layers"]]
236
- }
237
- st.session_state.construction_rerun_pending = True
238
- if cols[4].button("Copy", key=f"copy_lib_cons_{name}"):
239
  new_name = f"{name}_Project"
240
  counter = 1
241
  while new_name in st.session_state.project_data["constructions"]["project"] or new_name in construction_library.library_constructions:
@@ -257,9 +227,13 @@ def display_constructions_tables(construction_library: ConstructionLibrary):
257
  while new_mat_name in st.session_state.project_data["materials"]["project"] or new_mat_name in st.session_state.project_data["materials"]["library"]:
258
  new_mat_name = f"{material_name}_Project_{counter}"
259
  counter += 1
 
 
 
 
260
  new_material = Material(
261
  name=new_mat_name,
262
- category=MaterialCategory(library_material["category"]),
263
  conductivity=library_material["thermal_conductivity"],
264
  density=library_material["density"],
265
  specific_heat=library_material["specific_heat"],
@@ -280,11 +254,11 @@ def display_constructions_tables(construction_library: ConstructionLibrary):
280
  properties = calculate_construction_properties(new_layers, get_available_materials())
281
  new_construction = {
282
  "name": new_name,
283
- "type": construction["type"],
284
  "layers": new_layers,
285
  "u_value": properties["u_value"],
286
  "r_value": properties["r_value"],
287
  "thermal_mass": properties["thermal_mass"],
 
288
  "embodied_carbon": properties["embodied_carbon"],
289
  "cost": properties["cost"],
290
  "is_library": False
@@ -298,34 +272,30 @@ def display_constructions_tables(construction_library: ConstructionLibrary):
298
 
299
  st.subheader("Project Constructions")
300
  with st.container():
301
- project_constructions = list(st.session_state.project_data["constructions"]["project"].items()) # Changed to .items()
302
- if construction_filter != "All":
303
- project_constructions = [(name, c) for name, c in project_constructions if c["type"] == construction_filter]
304
  if project_constructions:
305
  cols = st.columns([2, 1, 1, 1, 1])
306
  cols[0].write("**Name**")
307
- cols[1].write("**Thermal Mass**")
308
  cols[2].write("**U-Value (W/m²·K)**")
309
  cols[3].write("**Edit**")
310
  cols[4].write("**Delete**")
311
- for name, construction in project_constructions: # Changed to unpack name and construction
312
  cols = st.columns([2, 1, 1, 1, 1])
313
- cols[0].write(name) # Use name directly
314
- cols[1].write(f"{construction.get('thermal_mass', 0.0):.1f}")
315
  cols[2].write(f"{construction.get('u_value', 0.0):.3f}")
316
  if cols[3].button("Edit", key=f"edit_proj_cons_{name}"):
317
  if st.session_state.get("rerun_trigger") != f"edit_cons_{name}":
318
  st.session_state.rerun_trigger = f"edit_cons_{name}"
319
  st.session_state.construction_editor = {
320
  "name": name,
321
- "component_type": construction["type"],
322
  "layers": [{"material_name": layer["material"], "thickness": layer["thickness"]} for layer in construction["layers"]],
323
  "is_edit": True,
324
  "original_name": name
325
  }
326
  st.session_state.construction_form_state = {
327
  "name": name,
328
- "component_type": construction["type"],
329
  "num_layers": len(construction["layers"]),
330
  "layers": [{"material_name": layer["material"], "thickness": layer["thickness"]} for layer in construction["layers"]]
331
  }
@@ -363,7 +333,6 @@ def display_construction_editor(construction_library: ConstructionLibrary):
363
  editor_state = st.session_state.get("construction_editor", {})
364
  form_state = st.session_state.get("construction_form_state", {
365
  "name": "",
366
- "component_type": "Wall",
367
  "num_layers": 1,
368
  "layers": [{"material_name": material_names[0] if material_names else "", "thickness": 0.1}]
369
  })
@@ -375,13 +344,6 @@ def display_construction_editor(construction_library: ConstructionLibrary):
375
  help="Unique construction identifier",
376
  key="construction_name_input"
377
  )
378
- component_type = st.selectbox(
379
- "Component Type",
380
- CONSTRUCTION_TYPES,
381
- index=CONSTRUCTION_TYPES.index(form_state.get("component_type", editor_state.get("component_type", "Wall"))),
382
- help="Building component type",
383
- key="construction_component_type_input"
384
- )
385
  num_layers = st.number_input(
386
  "Number of Layers",
387
  min_value=1,
@@ -484,11 +446,11 @@ def display_construction_editor(construction_library: ConstructionLibrary):
484
  properties = calculate_construction_properties(valid_layers, material_objects)
485
  new_construction = {
486
  "name": name,
487
- "type": component_type,
488
  "layers": valid_layers,
489
  "u_value": properties["u_value"],
490
  "r_value": properties["r_value"],
491
  "thermal_mass": properties["thermal_mass"],
 
492
  "embodied_carbon": properties["embodied_carbon"],
493
  "cost": properties["cost"],
494
  "is_library": False
@@ -504,7 +466,6 @@ def display_construction_editor(construction_library: ConstructionLibrary):
504
  st.session_state.construction_editor = {}
505
  st.session_state.construction_form_state = {
506
  "name": "",
507
- "component_type": "Wall",
508
  "num_layers": 1,
509
  "layers": [{"material_name": default_material, "thickness": 0.1}]
510
  }
@@ -521,7 +482,7 @@ def calculate_construction_properties(layers: List[Dict[str, Any]], materials: D
521
  Calculate the thermal properties of a construction based on its layers.
522
  """
523
  r_value = R_SI # Internal surface resistance
524
- thermal_mass = 0.0 # kJ/m²·K
525
  embodied_carbon = 0.0 # kg CO₂e/m²
526
  cost = 0.0 # $/m²
527
 
@@ -534,7 +495,7 @@ def calculate_construction_properties(layers: List[Dict[str, Any]], materials: D
534
  if material.conductivity > 0:
535
  r_value += thickness / material.conductivity
536
  # Thermal mass
537
- thermal_mass += material.density * material.specific_heat * thickness / 1000.0
538
  # Embodied carbon
539
  embodied_carbon += material.embodied_carbon * material.density * thickness
540
  # Cost
@@ -543,10 +504,19 @@ def calculate_construction_properties(layers: List[Dict[str, Any]], materials: D
543
  r_value += R_SE # External surface resistance
544
  u_value = 1.0 / r_value if r_value > 0 else 0.0
545
 
 
 
 
 
 
 
 
 
546
  return {
547
  "u_value": u_value,
548
  "r_value": r_value,
549
  "thermal_mass": thermal_mass,
 
550
  "embodied_carbon": embodied_carbon,
551
  "cost": cost
552
  }
@@ -569,7 +539,7 @@ def display_construction_help():
569
  st.markdown("""
570
  ### Construction Library Help
571
 
572
- This section allows you to create and manage multi-layer constructions for walls, roofs, and floors.
573
 
574
  **Key Concepts:**
575
 
@@ -577,14 +547,14 @@ def display_construction_help():
577
  * **Layers**: Individual material layers that make up a construction, defined from outside to inside.
578
  * **U-Value**: Overall heat transfer coefficient (W/m²·K), lower is better for insulation.
579
  * **R-Value**: Thermal resistance (m²·K/W), higher is better for insulation.
580
- * **Thermal Mass**: Heat storage capacity (kJ/m²·K), higher values provide better temperature stability.
581
 
582
  **Workflow:**
583
 
584
  1. Create new constructions or add existing ones from the library to your project.
585
  2. Define layers for each construction, selecting materials and specifying thicknesses.
586
  3. Calculate thermal properties to evaluate performance.
587
- 4. Use constructions in the Building Components section to define walls, roofs, and floors.
588
 
589
  **Tips:**
590
 
 
20
 
21
  # Import the centralized data module and materials library
22
  from app.m_c_data import get_default_constructions
23
+ from app.materials_library import get_available_materials, Material, MaterialCategory
24
 
25
  # Configure logging
26
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
27
  logger = logging.getLogger(__name__)
28
 
 
 
 
29
  # Surface resistances (EN ISO 6946 or ASHRAE)
30
  R_SI = 0.12 # Internal surface resistance (m²·K/W)
31
  R_SE = 0.04 # External surface resistance (m²·K/W)
 
39
  data = [
40
  {
41
  "Name": name,
 
42
  "U-Value (W/m²·K)": props.get("u_value", 0.0),
43
  "R-Value (m²·K/W)": props.get("r_value", 0.0),
44
+ "Thermal Mass Category": props.get("thermal_mass_category", "Low"),
45
  "Embodied Carbon (kgCO₂e/m²)": props.get("embodied_carbon", 0.0),
46
  "Cost (USD/m²)": props.get("cost", 0.0),
47
  "Layers": len(props.get("layers", []))
 
158
  # Display project constructions DataFrame
159
  st.subheader("Project Constructions")
160
  try:
 
161
  construction_df = construction_library.to_dataframe(st.session_state.project_data["constructions"]["project"])
 
 
162
  if not construction_df.empty:
163
  st.dataframe(construction_df, use_container_width=True)
164
  else:
 
192
 
193
  def display_constructions_tables(construction_library: ConstructionLibrary):
194
  """Display library and project constructions tables."""
 
 
 
 
195
  st.subheader("Library Constructions")
196
  with st.container():
197
+ library_constructions = list(construction_library.library_constructions.items())
198
+ cols = st.columns([2, 1, 1, 1])
 
 
199
  cols[0].write("**Name**")
200
+ cols[1].write("**Thermal Mass Category**")
201
  cols[2].write("**U-Value (W/m²·K)**")
202
+ cols[3].write("**Copy**")
203
+ for name, construction in library_constructions:
204
+ cols = st.columns([2, 1, 1, 1])
205
+ cols[0].write(name)
206
+ cols[1].write(construction.get("thermal_mass_category", "Low"))
 
207
  cols[2].write(f"{construction.get('u_value', 0.0):.3f}")
208
+ if cols[3].button("Copy", key=f"copy_lib_cons_{name}"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  new_name = f"{name}_Project"
210
  counter = 1
211
  while new_name in st.session_state.project_data["constructions"]["project"] or new_name in construction_library.library_constructions:
 
227
  while new_mat_name in st.session_state.project_data["materials"]["project"] or new_mat_name in st.session_state.project_data["materials"]["library"]:
228
  new_mat_name = f"{material_name}_Project_{counter}"
229
  counter += 1
230
+ category_str = library_material["category"].upper().replace("-", "_")
231
+ if category_str not in MaterialCategory.__members__:
232
+ st.error(f"Invalid category for material {material_name}: {library_material['category']}")
233
+ break
234
  new_material = Material(
235
  name=new_mat_name,
236
+ category=MaterialCategory[category_str],
237
  conductivity=library_material["thermal_conductivity"],
238
  density=library_material["density"],
239
  specific_heat=library_material["specific_heat"],
 
254
  properties = calculate_construction_properties(new_layers, get_available_materials())
255
  new_construction = {
256
  "name": new_name,
 
257
  "layers": new_layers,
258
  "u_value": properties["u_value"],
259
  "r_value": properties["r_value"],
260
  "thermal_mass": properties["thermal_mass"],
261
+ "thermal_mass_category": properties["thermal_mass_category"],
262
  "embodied_carbon": properties["embodied_carbon"],
263
  "cost": properties["cost"],
264
  "is_library": False
 
272
 
273
  st.subheader("Project Constructions")
274
  with st.container():
275
+ project_constructions = list(st.session_state.project_data["constructions"]["project"].items())
 
 
276
  if project_constructions:
277
  cols = st.columns([2, 1, 1, 1, 1])
278
  cols[0].write("**Name**")
279
+ cols[1].write("**Thermal Mass Category**")
280
  cols[2].write("**U-Value (W/m²·K)**")
281
  cols[3].write("**Edit**")
282
  cols[4].write("**Delete**")
283
+ for name, construction in project_constructions:
284
  cols = st.columns([2, 1, 1, 1, 1])
285
+ cols[0].write(name)
286
+ cols[1].write(construction.get("thermal_mass_category", "Low"))
287
  cols[2].write(f"{construction.get('u_value', 0.0):.3f}")
288
  if cols[3].button("Edit", key=f"edit_proj_cons_{name}"):
289
  if st.session_state.get("rerun_trigger") != f"edit_cons_{name}":
290
  st.session_state.rerun_trigger = f"edit_cons_{name}"
291
  st.session_state.construction_editor = {
292
  "name": name,
 
293
  "layers": [{"material_name": layer["material"], "thickness": layer["thickness"]} for layer in construction["layers"]],
294
  "is_edit": True,
295
  "original_name": name
296
  }
297
  st.session_state.construction_form_state = {
298
  "name": name,
 
299
  "num_layers": len(construction["layers"]),
300
  "layers": [{"material_name": layer["material"], "thickness": layer["thickness"]} for layer in construction["layers"]]
301
  }
 
333
  editor_state = st.session_state.get("construction_editor", {})
334
  form_state = st.session_state.get("construction_form_state", {
335
  "name": "",
 
336
  "num_layers": 1,
337
  "layers": [{"material_name": material_names[0] if material_names else "", "thickness": 0.1}]
338
  })
 
344
  help="Unique construction identifier",
345
  key="construction_name_input"
346
  )
 
 
 
 
 
 
 
347
  num_layers = st.number_input(
348
  "Number of Layers",
349
  min_value=1,
 
446
  properties = calculate_construction_properties(valid_layers, material_objects)
447
  new_construction = {
448
  "name": name,
 
449
  "layers": valid_layers,
450
  "u_value": properties["u_value"],
451
  "r_value": properties["r_value"],
452
  "thermal_mass": properties["thermal_mass"],
453
+ "thermal_mass_category": properties["thermal_mass_category"],
454
  "embodied_carbon": properties["embodied_carbon"],
455
  "cost": properties["cost"],
456
  "is_library": False
 
466
  st.session_state.construction_editor = {}
467
  st.session_state.construction_form_state = {
468
  "name": "",
 
469
  "num_layers": 1,
470
  "layers": [{"material_name": default_material, "thickness": 0.1}]
471
  }
 
482
  Calculate the thermal properties of a construction based on its layers.
483
  """
484
  r_value = R_SI # Internal surface resistance
485
+ thermal_mass = 0.0 # J/m²·K
486
  embodied_carbon = 0.0 # kg CO₂e/m²
487
  cost = 0.0 # $/m²
488
 
 
495
  if material.conductivity > 0:
496
  r_value += thickness / material.conductivity
497
  # Thermal mass
498
+ thermal_mass += material.density * material.specific_heat * thickness
499
  # Embodied carbon
500
  embodied_carbon += material.embodied_carbon * material.density * thickness
501
  # Cost
 
504
  r_value += R_SE # External surface resistance
505
  u_value = 1.0 / r_value if r_value > 0 else 0.0
506
 
507
+ # Categorize thermal mass
508
+ if thermal_mass < 30000:
509
+ thermal_mass_category = "Low"
510
+ elif 30000 <= thermal_mass <= 90000:
511
+ thermal_mass_category = "Medium"
512
+ else:
513
+ thermal_mass_category = "High"
514
+
515
  return {
516
  "u_value": u_value,
517
  "r_value": r_value,
518
  "thermal_mass": thermal_mass,
519
+ "thermal_mass_category": thermal_mass_category,
520
  "embodied_carbon": embodied_carbon,
521
  "cost": cost
522
  }
 
539
  st.markdown("""
540
  ### Construction Library Help
541
 
542
+ This section allows you to create and manage multi-layer constructions for building envelope components.
543
 
544
  **Key Concepts:**
545
 
 
547
  * **Layers**: Individual material layers that make up a construction, defined from outside to inside.
548
  * **U-Value**: Overall heat transfer coefficient (W/m²·K), lower is better for insulation.
549
  * **R-Value**: Thermal resistance (m²·K/W), higher is better for insulation.
550
+ * **Thermal Mass Category**: Heat storage capacity, categorized as Low (< 30,000 J/m²·K), Medium (30,000–90,000 J/m²·K), or High (> 90,000 J/m²·K).
551
 
552
  **Workflow:**
553
 
554
  1. Create new constructions or add existing ones from the library to your project.
555
  2. Define layers for each construction, selecting materials and specifying thicknesses.
556
  3. Calculate thermal properties to evaluate performance.
557
+ 4. Use constructions in the Building Components section to define building elements.
558
 
559
  **Tips:**
560