mabuseif commited on
Commit
f692fa0
verified
1 Parent(s): 1fa4b68

Update app/materials_library.py

Browse files
Files changed (1) hide show
  1. app/materials_library.py +94 -89
app/materials_library.py CHANGED
@@ -56,7 +56,7 @@ DEFAULT_MATERIALS = {
56
  "density": 1920.0,
57
  "specific_heat": 840.0,
58
  "default_thickness": 0.1,
59
- "embodied_carbon": 240,
60
  "cost": 180.0,
61
  "absorptivity": 0.65,
62
  "emissivity": 0.90,
@@ -345,12 +345,13 @@ def categorize_thermal_mass(thermal_mass: float) -> str:
345
  else:
346
  return "High"
347
 
348
- def get_stable_button_key(prefix: str, name: str, action: str) -> str:
349
- """Generate a stable button key based on prefix, name, and action."""
350
  import hashlib
351
- key_string = f"{prefix}_{name}_{action}"
 
352
  hash_key = hashlib.md5(key_string.encode()).hexdigest()[:8]
353
- return f"{prefix}_{action}_{hash_key}"
354
 
355
  def display_materials_page():
356
  """
@@ -478,14 +479,14 @@ def display_materials_tab():
478
  st.session_state.material_form_state = {
479
  "name": name,
480
  "category": material["category"],
481
- "thermal_conductivity": material["thermal_conductivity"],
482
- "density": material["density"],
483
- "specific_heat": material["specific_heat"],
484
- "default_thickness": material["default_thickness"],
485
- "embodied_carbon": material["embodied_carbon"],
486
- "cost": material["cost"],
487
- "absorptivity": material["absorptivity"],
488
- "emissivity": material["emissivity"],
489
  "colour": material["colour"]
490
  }
491
  st.session_state.active_tab = "Materials"
@@ -558,14 +559,14 @@ def display_materials_tab():
558
  st.session_state.material_form_state = {
559
  "name": name,
560
  "category": material["category"],
561
- "thermal_conductivity": material["thermal_conductivity"],
562
- "density": material["density"],
563
- "specific_heat": material["specific_heat"],
564
- "default_thickness": material["default_thickness"],
565
- "embodied_carbon": material["embodied_carbon"],
566
- "cost": material["cost"],
567
- "absorptivity": material["absorptivity"],
568
- "emissivity": material["emissivity"],
569
  "colour": material["colour"]
570
  }
571
  st.session_state.active_tab = "Materials"
@@ -674,12 +675,12 @@ def display_fenestrations_tab():
674
  st.session_state.fenestration_form_state = {
675
  "name": name,
676
  "type": fenestration["type"],
677
- "u_value": fenestration["u_value"],
678
- "shgc": fenestration["shgc"],
679
- "visible_trans": fenestration["visible_transmittance"],
680
- "thickness": fenestration["thickness"],
681
- "embodied_carbon": fenestration["embodied_carbon"],
682
- "cost": fenestration["cost"]
683
  }
684
  st.session_state.active_tab = "Fenestrations"
685
  st.session_state.rerun_pending = True
@@ -745,12 +746,12 @@ def display_fenestrations_tab():
745
  st.session_state.fenestration_form_state = {
746
  "name": name,
747
  "type": fenestration["type"],
748
- "u_value": fenestration["u_value"],
749
- "shgc": fenestration["shgc"],
750
- "visible_trans": fenestration["visible_transmittance"],
751
- "thickness": fenestration["thickness"],
752
- "embodied_carbon": fenestration["embodied_carbon"],
753
- "cost": fenestration["cost"]
754
  }
755
  st.session_state.active_tab = "Fenestrations"
756
  st.session_state.rerun_pending = True
@@ -758,13 +759,13 @@ def display_fenestrations_tab():
758
  if cols[4].button("Delete", key=delete_key):
759
  is_in_use = check_fenestration_in_use(name)
760
  if is_in_use:
761
- st.error(f"Cannot delete fenestration_fenestration '{name}' because it is in use in components.")
762
  else:
763
  del st.session_state.project_data["fenestrations"]["project"][name]
764
  st.success(f"Fenestration '{name}' deleted from project.")
765
- st.logger.info(f"Deleted fenestration '{name}' from project")
766
  st.session_state.rerun_pending = True
767
-
768
  else:
769
  st.info("No project fenestrations in the selected type.")
770
 
@@ -778,7 +779,7 @@ def display_fenestrations_tab():
778
  "Type": props["type"],
779
  "U-Value (W/m虏路K)": props["u_value"],
780
  "SHGC": props["shgc"],
781
- "VisibleLight Transmittance": props["visible_transmittance"],
782
  "Thickness (m)": props["thickness"],
783
  "Embodied Carbon (kg/m虏)": props["embodied_carbon"],
784
  "Cost (USD/m虏)": props["cost"]
@@ -814,7 +815,7 @@ def initialize_materials():
814
  "specific_heat": 1000.0,
815
  "default_thickness": 0.05,
816
  "embodied_carbon": 100.0,
817
- "cost": 100.100,
818
  "absorptivity": 0.60,
819
  "emissivity": 0.90,
820
  "colour": "Medium",
@@ -831,10 +832,10 @@ def initialize_materials():
831
  "density": 1000.0,
832
  "specific_heat": 1000.0,
833
  "default_thickness": 0.05,
834
- "embodied_carbon": "",
835
- "cost": "",
836
- "absorptivity": 0.6,
837
- "emissivity": "",
838
  "colour": "Medium"
839
  }
840
 
@@ -850,7 +851,7 @@ def initialize_fenestrations():
850
  if not st.session_state.project_data["fenestrations"]["library"]:
851
  st.session_state.project_data["fenestrations"]["library"] = DEFAULT_FENESTRATIONS.copy()
852
 
853
- if "fenestration_editor_form" not in st.session_state:
854
  st.session_state.fenestration_editor = {
855
  "name": "",
856
  "type": FENESTRATION_TYPES[0],
@@ -873,8 +874,8 @@ def initialize_fenestrations():
873
  "shgc": 0.7,
874
  "visible_trans": 0.8,
875
  "thickness": 0.024,
876
- "embodied_carbon": "",
877
- "cost": ""
878
  }
879
 
880
  def display_material_editor():
@@ -907,7 +908,7 @@ def display_material_editor():
907
  "Thermal Conductivity (W/m路K)",
908
  min_value=0.001,
909
  max_value=1000.0,
910
- value=float(form_state.get("thermal_conductivity", editor_state["thermal_conductivity"])),
911
  format="%.3f",
912
  help="Thermal conductivity in W/m路K. Lower values indicate better insulation.",
913
  disabled=is_library
@@ -917,7 +918,7 @@ def display_material_editor():
917
  "Density (kg/m鲁)",
918
  min_value=1.0,
919
  max_value=20000.0,
920
- value=float(form_state.get("density", editor_state["density"])),
921
  format="%.1f",
922
  help="Material density in kg/m鲁.",
923
  disabled=is_library
@@ -928,7 +929,7 @@ def display_material_editor():
928
  "Specific Heat (J/kg路K)",
929
  min_value=100.0,
930
  max_value=10000.0,
931
- value=float(form_state.get("specific_heat", editor_state["specific_heat"])),
932
  format="%.1f",
933
  help="Specific heat capacity in J/kg路K. Higher values indicate better thermal mass.",
934
  disabled=is_library
@@ -938,7 +939,7 @@ def display_material_editor():
938
  "Thickness (m)",
939
  min_value=0.001,
940
  max_value=0.5,
941
- value=float(form_state.get("default_thickness", editor_state["default_thickness"])),
942
  format="%.3f",
943
  help="Thickness for this material in meters.",
944
  disabled=is_library
@@ -948,7 +949,7 @@ def display_material_editor():
948
  "Absorptivity",
949
  min_value=0.0,
950
  max_value=1.0,
951
- value=float(form_state.get("absorptivity", editor_state["absorptivity"])),
952
  format="%.2f",
953
  help="Solar radiation absorbed (0-1).",
954
  disabled=is_library
@@ -961,14 +962,14 @@ def display_material_editor():
961
  "Emissivity",
962
  min_value=0.0,
963
  max_value=1.0,
964
- value=float(form_state.get("emissivity", editor_state["emissivity"])),
965
  format="%.2f",
966
  help="Ratio of radiation emitted (0-1).",
967
  disabled=is_library
968
  )
969
 
970
  with col2:
971
- colour_index = COLOUR_CATEGORIES.index(form_state.get("colour", editor_state["colour"])) if form_state.get("colour", editor_state["colour"]) in COLOUR_CATEGORIES else 0
972
  colour = st.selectbox(
973
  "Colour Category",
974
  COLOUR_CATEGORIES,
@@ -985,7 +986,7 @@ def display_material_editor():
985
  "Embodied Carbon (kg CO鈧俥/m鲁)",
986
  min_value=0.0,
987
  max_value=10000.0,
988
- value=float(form_state.get("embodied_carbon", editor_state.get("embodied_carbon", ""))),
989
  format="%.1f",
990
  help="Embodied carbon in kg CO鈧俥 per cubic meter.",
991
  disabled=is_library
@@ -996,7 +997,7 @@ def display_material_editor():
996
  "Cost (USD/m鲁)",
997
  min_value=0.0,
998
  max_value=10000.0,
999
- value=float(form_state.get("cost", editor_state.get("cost", ""))),
1000
  format="%.1f",
1001
  help="Material cost in USD per cubic meter.",
1002
  disabled=is_library
@@ -1096,9 +1097,9 @@ def display_fenestration_editor():
1096
  "U-Value (W/m虏路K)",
1097
  min_value=0.1,
1098
  max_value=10.0,
1099
- value=float(form_state.get("u_value", editor_state.get("u_value", ""))),
1100
  format="%.2f",
1101
- help="U-value in W/m虏路K. value",
1102
  disabled=is_library
1103
  )
1104
 
@@ -1107,7 +1108,7 @@ def display_fenestration_editor():
1107
  "Solar Heat Gain Coefficient (SHGC)",
1108
  min_value=0.0,
1109
  max_value=1.0,
1110
- value=float(form_state.get("shgc", editor_state.get("shgc", ""))),
1111
  format="%.2f",
1112
  help="Solar Heat Gain Coefficient (0-1).",
1113
  disabled=is_library
@@ -1117,7 +1118,7 @@ def display_fenestration_editor():
1117
  "Visible Transmittance",
1118
  min_value=0.0,
1119
  max_value=1.0,
1120
- value=float(form_state.get("visible_trans", editor_state.get("visible_trans", ""))),
1121
  format="%.2f",
1122
  help="Visible light transmission (0-1).",
1123
  disabled=is_library
@@ -1127,7 +1128,7 @@ def display_fenestration_editor():
1127
  "Thickness (m)",
1128
  min_value=0.001,
1129
  max_value=0.1,
1130
- value=float(form_state.get("thickness", editor_state.get("thickness", ""))),
1131
  format="%.3f",
1132
  help="Thickness in meters.",
1133
  disabled=is_library
@@ -1142,7 +1143,7 @@ def display_fenestration_editor():
1142
  "Embodied Carbon (kg CO鈧俥/m虏)",
1143
  min_value=0.0,
1144
  max_value=5000.0,
1145
- value=float(form_state.get("embodied_carbon", editor_state.get("embodied_carbon", ""))),
1146
  format="%.1f",
1147
  help="Embodied carbon in kg CO鈧俥/m虏.",
1148
  disabled=is_library
@@ -1153,7 +1154,7 @@ def display_fenestration_editor():
1153
  "Cost (USD/m虏)",
1154
  min_value=0.0,
1155
  max_value=5000.0,
1156
- value=float(form_state.get("cost", editor_state.get("cost", ""))),
1157
  format="%.1f",
1158
  help="Fenestration cost in USD/m虏.",
1159
  disabled=is_library
@@ -1199,7 +1200,7 @@ def display_fenestration_editor():
1199
  }
1200
  if editor_state["edit_mode"]:
1201
  original_name = editor_state["original_name"]
1202
- if original_name != st.name:
1203
  del st.session_state.project_data["fenestrations"]["project"][original_name]
1204
  st.session_state.project_data["fenestrations"]["project"][name] = fenestration_data
1205
  st.success(f"Fenestration '{name}' updated successfully.")
@@ -1280,7 +1281,8 @@ def validate_fenestration(
1280
  ) -> Tuple[bool, str]:
1281
  """
1282
  Validate fenestration inputs.
1283
- Returns (success, message) tuple."""
 
1284
  if not name or name.strip() == "":
1285
  return False, "Fenestration name is required."
1286
 
@@ -1319,24 +1321,24 @@ def reset_material_editor():
1319
  "density": 1000.0,
1320
  "specific_heat": 1000.0,
1321
  "default_thickness": 0.05,
1322
- "embodied_carbon": "",
1323
- "cost": "",
1324
  "absorptivity": 0.60,
1325
- "emissivity": "",
1326
- "colour": ""
1327
  }
1328
  st.session_state.material_editor = {
1329
  "name": "",
1330
  "category": MATERIAL_CATEGORIES[0],
1331
- "thermal_conductivity": "",
1332
- "density": 0.0,
1333
- "specific_heat": "",
1334
- "default_thickness": "",
1335
- "embodied_carbon": "",
1336
- "cost": "",
1337
- "absorptivity": "",
1338
- "emissivity": "",
1339
- "colour": "",
1340
  "edit_mode": False,
1341
  "original_name": "",
1342
  "is_library": False
@@ -1349,22 +1351,25 @@ def reset_fenestration_editor():
1349
  st.session_state.fenestration_form_state = {
1350
  "name": "",
1351
  "type": FENESTRATION_TYPES[0],
1352
- "u_value": "",
1353
- "shgc": "",
1354
- "visible_trans": "",
1355
- "thickness": "",
1356
- "embodied_carbon": "",
1357
- "cost": ""
1358
  }
1359
- st.session_state.fenestration_form_state = {
1360
  "name": "",
1361
  "type": FENESTRATION_TYPES[0],
1362
- "u_value": "",
1363
- "shgc": "",
1364
- "visible_trans": "",
1365
- "thickness": "",
1366
- "embodied_carbon": "",
1367
- "cost": ""
 
 
 
1368
  }
1369
  st.session_state.fenestration_action = {"action": None, "id": None}
1370
  st.session_state.rerun_trigger = None
 
56
  "density": 1920.0,
57
  "specific_heat": 840.0,
58
  "default_thickness": 0.1,
59
+ "embodied_carbon": 240.0,
60
  "cost": 180.0,
61
  "absorptivity": 0.65,
62
  "emissivity": 0.90,
 
345
  else:
346
  return "High"
347
 
348
+ def get_stable_button_key(prefix: str, name: str, action: str, unique_id: str = None) -> str:
349
+ """Generate a stable button key based on prefix, name, action, and optional unique identifier."""
350
  import hashlib
351
+ unique_id = unique_id or str(uuid.uuid4())[:8] # Generate unique ID if not provided
352
+ key_string = f"{prefix}_{name}_{action}_{unique_id}"
353
  hash_key = hashlib.md5(key_string.encode()).hexdigest()[:8]
354
+ return f"{prefix}_{action}_{name}_{hash_key}"
355
 
356
  def display_materials_page():
357
  """
 
479
  st.session_state.material_form_state = {
480
  "name": name,
481
  "category": material["category"],
482
+ "thermal_conductivity": float(material["thermal_conductivity"]),
483
+ "density": float(material["density"]),
484
+ "specific_heat": float(material["specific_heat"]),
485
+ "default_thickness": float(material["default_thickness"]),
486
+ "embodied_carbon": float(material["embodied_carbon"]),
487
+ "cost": float(material["cost"]),
488
+ "absorptivity": float(material["absorptivity"]),
489
+ "emissivity": float(material["emissivity"]),
490
  "colour": material["colour"]
491
  }
492
  st.session_state.active_tab = "Materials"
 
559
  st.session_state.material_form_state = {
560
  "name": name,
561
  "category": material["category"],
562
+ "thermal_conductivity": float(material["thermal_conductivity"]),
563
+ "density": float(material["density"]),
564
+ "specific_heat": float(material["specific_heat"]),
565
+ "default_thickness": float(material["default_thickness"]),
566
+ "embodied_carbon": float(material["embodied_carbon"]),
567
+ "cost": float(material["cost"]),
568
+ "absorptivity": float(material["absorptivity"]),
569
+ "emissivity": float(material["emissivity"]),
570
  "colour": material["colour"]
571
  }
572
  st.session_state.active_tab = "Materials"
 
675
  st.session_state.fenestration_form_state = {
676
  "name": name,
677
  "type": fenestration["type"],
678
+ "u_value": float(fenestration["u_value"]),
679
+ "shgc": float(fenestration["shgc"]),
680
+ "visible_trans": float(fenestration["visible_transmittance"]),
681
+ "thickness": float(fenestration["thickness"]),
682
+ "embodied_carbon": float(fenestration["embodied_carbon"]),
683
+ "cost": float(fenestration["cost"])
684
  }
685
  st.session_state.active_tab = "Fenestrations"
686
  st.session_state.rerun_pending = True
 
746
  st.session_state.fenestration_form_state = {
747
  "name": name,
748
  "type": fenestration["type"],
749
+ "u_value": float(fenestration["u_value"]),
750
+ "shgc": float(fenestration["shgc"]),
751
+ "visible_trans": float(fenestration["visible_transmittance"]),
752
+ "thickness": float(fenestration["thickness"]),
753
+ "embodied_carbon": float(fenestration["embodied_carbon"]),
754
+ "cost": float(fenestration["cost"])
755
  }
756
  st.session_state.active_tab = "Fenestrations"
757
  st.session_state.rerun_pending = True
 
759
  if cols[4].button("Delete", key=delete_key):
760
  is_in_use = check_fenestration_in_use(name)
761
  if is_in_use:
762
+ st.error(f"Cannot delete fenestration '{name}' because it is in use in components.")
763
  else:
764
  del st.session_state.project_data["fenestrations"]["project"][name]
765
  st.success(f"Fenestration '{name}' deleted from project.")
766
+ logger.info(f"Deleted fenestration '{name}' from project")
767
  st.session_state.rerun_pending = True
768
+
769
  else:
770
  st.info("No project fenestrations in the selected type.")
771
 
 
779
  "Type": props["type"],
780
  "U-Value (W/m虏路K)": props["u_value"],
781
  "SHGC": props["shgc"],
782
+ "Visible Transmittance": props["visible_transmittance"],
783
  "Thickness (m)": props["thickness"],
784
  "Embodied Carbon (kg/m虏)": props["embodied_carbon"],
785
  "Cost (USD/m虏)": props["cost"]
 
815
  "specific_heat": 1000.0,
816
  "default_thickness": 0.05,
817
  "embodied_carbon": 100.0,
818
+ "cost": 100.0,
819
  "absorptivity": 0.60,
820
  "emissivity": 0.90,
821
  "colour": "Medium",
 
832
  "density": 1000.0,
833
  "specific_heat": 1000.0,
834
  "default_thickness": 0.05,
835
+ "embodied_carbon": 100.0,
836
+ "cost": 100.0,
837
+ "absorptivity": 0.60,
838
+ "emissivity": 0.90,
839
  "colour": "Medium"
840
  }
841
 
 
851
  if not st.session_state.project_data["fenestrations"]["library"]:
852
  st.session_state.project_data["fenestrations"]["library"] = DEFAULT_FENESTRATIONS.copy()
853
 
854
+ if "fenestration_editor" not in st.session_state:
855
  st.session_state.fenestration_editor = {
856
  "name": "",
857
  "type": FENESTRATION_TYPES[0],
 
874
  "shgc": 0.7,
875
  "visible_trans": 0.8,
876
  "thickness": 0.024,
877
+ "embodied_carbon": 900.0,
878
+ "cost": 200.0
879
  }
880
 
881
  def display_material_editor():
 
908
  "Thermal Conductivity (W/m路K)",
909
  min_value=0.001,
910
  max_value=1000.0,
911
+ value=float(form_state.get("thermal_conductivity", editor_state.get("thermal_conductivity", 0.5))),
912
  format="%.3f",
913
  help="Thermal conductivity in W/m路K. Lower values indicate better insulation.",
914
  disabled=is_library
 
918
  "Density (kg/m鲁)",
919
  min_value=1.0,
920
  max_value=20000.0,
921
+ value=float(form_state.get("density", editor_state.get("density", 1000.0))),
922
  format="%.1f",
923
  help="Material density in kg/m鲁.",
924
  disabled=is_library
 
929
  "Specific Heat (J/kg路K)",
930
  min_value=100.0,
931
  max_value=10000.0,
932
+ value=float(form_state.get("specific_heat", editor_state.get("specific_heat", 1000.0))),
933
  format="%.1f",
934
  help="Specific heat capacity in J/kg路K. Higher values indicate better thermal mass.",
935
  disabled=is_library
 
939
  "Thickness (m)",
940
  min_value=0.001,
941
  max_value=0.5,
942
+ value=float(form_state.get("default_thickness", editor_state.get("default_thickness", 0.05))),
943
  format="%.3f",
944
  help="Thickness for this material in meters.",
945
  disabled=is_library
 
949
  "Absorptivity",
950
  min_value=0.0,
951
  max_value=1.0,
952
+ value=float(form_state.get("absorptivity", editor_state.get("absorptivity", 0.60))),
953
  format="%.2f",
954
  help="Solar radiation absorbed (0-1).",
955
  disabled=is_library
 
962
  "Emissivity",
963
  min_value=0.0,
964
  max_value=1.0,
965
+ value=float(form_state.get("emissivity", editor_state.get("emissivity", 0.90))),
966
  format="%.2f",
967
  help="Ratio of radiation emitted (0-1).",
968
  disabled=is_library
969
  )
970
 
971
  with col2:
972
+ colour_index = COLOUR_CATEGORIES.index(form_state.get("colour", editor_state.get("colour", "Medium"))) if form_state.get("colour", editor_state.get("colour", "Medium")) in COLOUR_CATEGORIES else 0
973
  colour = st.selectbox(
974
  "Colour Category",
975
  COLOUR_CATEGORIES,
 
986
  "Embodied Carbon (kg CO鈧俥/m鲁)",
987
  min_value=0.0,
988
  max_value=10000.0,
989
+ value=float(form_state.get("embodied_carbon", editor_state.get("embodied_carbon", 100.0))),
990
  format="%.1f",
991
  help="Embodied carbon in kg CO鈧俥 per cubic meter.",
992
  disabled=is_library
 
997
  "Cost (USD/m鲁)",
998
  min_value=0.0,
999
  max_value=10000.0,
1000
+ value=float(form_state.get("cost", editor_state.get("cost", 100.0))),
1001
  format="%.1f",
1002
  help="Material cost in USD per cubic meter.",
1003
  disabled=is_library
 
1097
  "U-Value (W/m虏路K)",
1098
  min_value=0.1,
1099
  max_value=10.0,
1100
+ value=float(form_state.get("u_value", editor_state.get("u_value", 2.8))),
1101
  format="%.2f",
1102
+ help="U-value in W/m虏路K.",
1103
  disabled=is_library
1104
  )
1105
 
 
1108
  "Solar Heat Gain Coefficient (SHGC)",
1109
  min_value=0.0,
1110
  max_value=1.0,
1111
+ value=float(form_state.get("shgc", editor_state.get("shgc", 0.7))),
1112
  format="%.2f",
1113
  help="Solar Heat Gain Coefficient (0-1).",
1114
  disabled=is_library
 
1118
  "Visible Transmittance",
1119
  min_value=0.0,
1120
  max_value=1.0,
1121
+ value=float(form_state.get("visible_trans", editor_state.get("visible_trans", 0.8))),
1122
  format="%.2f",
1123
  help="Visible light transmission (0-1).",
1124
  disabled=is_library
 
1128
  "Thickness (m)",
1129
  min_value=0.001,
1130
  max_value=0.1,
1131
+ value=float(form_state.get("thickness", editor_state.get("thickness", 0.024))),
1132
  format="%.3f",
1133
  help="Thickness in meters.",
1134
  disabled=is_library
 
1143
  "Embodied Carbon (kg CO鈧俥/m虏)",
1144
  min_value=0.0,
1145
  max_value=5000.0,
1146
+ value=float(form_state.get("embodied_carbon", editor_state.get("embodied_carbon", 900.0))),
1147
  format="%.1f",
1148
  help="Embodied carbon in kg CO鈧俥/m虏.",
1149
  disabled=is_library
 
1154
  "Cost (USD/m虏)",
1155
  min_value=0.0,
1156
  max_value=5000.0,
1157
+ value=float(form_state.get("cost", editor_state.get("cost", 200.0))),
1158
  format="%.1f",
1159
  help="Fenestration cost in USD/m虏.",
1160
  disabled=is_library
 
1200
  }
1201
  if editor_state["edit_mode"]:
1202
  original_name = editor_state["original_name"]
1203
+ if original_name != name:
1204
  del st.session_state.project_data["fenestrations"]["project"][original_name]
1205
  st.session_state.project_data["fenestrations"]["project"][name] = fenestration_data
1206
  st.success(f"Fenestration '{name}' updated successfully.")
 
1281
  ) -> Tuple[bool, str]:
1282
  """
1283
  Validate fenestration inputs.
1284
+ Returns (success, message) tuple.
1285
+ """
1286
  if not name or name.strip() == "":
1287
  return False, "Fenestration name is required."
1288
 
 
1321
  "density": 1000.0,
1322
  "specific_heat": 1000.0,
1323
  "default_thickness": 0.05,
1324
+ "embodied_carbon": 100.0,
1325
+ "cost": 100.0,
1326
  "absorptivity": 0.60,
1327
+ "emissivity": 0.90,
1328
+ "colour": "Medium"
1329
  }
1330
  st.session_state.material_editor = {
1331
  "name": "",
1332
  "category": MATERIAL_CATEGORIES[0],
1333
+ "thermal_conductivity": 0.5,
1334
+ "density": 1000.0,
1335
+ "specific_heat": 1000.0,
1336
+ "default_thickness": 0.05,
1337
+ "embodied_carbon": 100.0,
1338
+ "cost": 100.0,
1339
+ "absorptivity": 0.60,
1340
+ "emissivity": 0.90,
1341
+ "colour": "Medium",
1342
  "edit_mode": False,
1343
  "original_name": "",
1344
  "is_library": False
 
1351
  st.session_state.fenestration_form_state = {
1352
  "name": "",
1353
  "type": FENESTRATION_TYPES[0],
1354
+ "u_value": 2.8,
1355
+ "shgc": 0.7,
1356
+ "visible_trans": 0.8,
1357
+ "thickness": 0.024,
1358
+ "embodied_carbon": 900.0,
1359
+ "cost": 200.0
1360
  }
1361
+ st.session_state.fenestration_editor = {
1362
  "name": "",
1363
  "type": FENESTRATION_TYPES[0],
1364
+ "u_value": 2.8,
1365
+ "shgc": 0.7,
1366
+ "visible_trans": 0.8,
1367
+ "thickness": 0.024,
1368
+ "embodied_carbon": 900.0,
1369
+ "cost": 200.0,
1370
+ "edit_mode": False,
1371
+ "original_name": "",
1372
+ "is_library": False
1373
  }
1374
  st.session_state.fenestration_action = {"action": None, "id": None}
1375
  st.session_state.rerun_trigger = None