Spaces:
Sleeping
Sleeping
| # Description: Finding the right heating system for a building based on the energy demand, the age of the building and the size of the building. | |
| import pandas as pd | |
| import os | |
| import streamlit as st | |
| from data_utils.loader import load_heatingsystem_csv | |
| from utils.misc import parsefloat, apply_technology_name_language | |
| def determine_heatingsystem_filename(scenario_id): | |
| return f"Szen{scenario_id}_Heizsystem.csv" | |
| def determine_building_state(energy_demand): | |
| energy_demand = float(energy_demand) | |
| if 0 <= energy_demand <= 100: | |
| return "NB" | |
| elif 100 < energy_demand <= 200: | |
| return "ABsaniert" | |
| else: | |
| return "ABunsaniert" | |
| def find_suitable_heating_systems( | |
| energy_demand, year_built, area, scenario_id="A", heat_load_user=None, building_state="ABsaniert" | |
| ): | |
| filename = determine_heatingsystem_filename(scenario_id) | |
| df = load_heatingsystem_csv(filename) | |
| df["Effizienz"] = df[f"Effizienz_{building_state}"] | |
| relevant_columns = [ | |
| 'Heizsystem', 'Leistung (kW)', 'Investitionskosten (€)', 'Betriebsjahre', 'Effizienz', | |
| 'Emissionen (kg_CO2/kWh)', 'Preisänderungsfaktor Inv', 'Betriebskosten (€/kWh)', 'Preisänderungsfaktor Bedarf', | |
| 'Fixkosten O+M (€/kW)', 'Preisänderungsrate O+M', 'Emissionsänderungsfaktor', 'Förderung' | |
| ] | |
| df = df[relevant_columns] | |
| df.columns = [ | |
| "Name", "Leistung", "Investitionskosten", "Betriebsdauer", "Effizienz", "Emissionen", | |
| "Preisänderungsfaktor_Inv", "Betriebskosten", "Preisänderungsfaktor_Bedarf", | |
| "Fixkosten_O+M", "Preisänderungsfaktor_O+M", "Emissionsänderungsfaktor", "Förderung" | |
| ] | |
| # Berechnung Heizlast | |
| if heat_load_user is not None: | |
| heat_load = float(heat_load_user) | |
| else: | |
| heat_load = calc_heat_load(area, energy_demand) | |
| # ACHTUNG: Jetzt die neuen Namen verwenden! | |
| df['Leistung'] = pd.to_numeric(df['Leistung'], errors='coerce') | |
| df = df.dropna(subset=['Leistung']) | |
| df = df[df['Leistung'] >= heat_load] | |
| # ... wie gehabt weiter (jetzt mit neuen Namen!) | |
| df_result = df.loc[df.groupby('Name')['Leistung'].idxmin()] | |
| heizsystem_reihenfolge = [ | |
| 'Luft-Wasser Wärmepumpe', 'Wasser-Wasser Wärmepumpe', | |
| 'Sole-Wasser Wärmepumpe', 'Hybrid-Wärmepumpe', 'Pelletheizung', 'Holzhackschnitzelheizung', | |
| 'Wasserstoffheizung', 'Gasheizung', 'Ölheizung' | |
| ] | |
| df_result['Name'] = pd.Categorical(df_result['Name'], categories=heizsystem_reihenfolge, ordered=True) | |
| df_result = df_result.sort_values(by='Name') | |
| return df_result | |
| # VDI 2067, Blatt 2: | |
| full_load_hours_SFH = 2100 | |
| full_load_hours_MFH = 2000 | |
| def calc_heat_load(area, energy_demand): | |
| total_energy_demand = energy_demand*area | |
| # Differentiate between SFH and MFH. We use 400 m² as the threshold. Could be changed or even interpolated. | |
| if area < 400: | |
| full_load_hours = full_load_hours_SFH | |
| else: | |
| full_load_hours = full_load_hours_MFH | |
| heat_load = total_energy_demand / full_load_hours | |
| return heat_load | |
| def load_or_calculate_heating_systems( | |
| submitted, specific_energy_demand, year_built, floor_area, scenario_id, | |
| interest_rate, observation_period, emission_price_change_factor, emission_cost, ui, heat_load_user, building_state): | |
| if submitted or st.session_state.df_heizsysteme is None: | |
| try: | |
| df = find_suitable_heating_systems(specific_energy_demand, year_built, floor_area, scenario_id, heat_load_user, building_state) | |
| if df.empty: | |
| st.error(ui["output"]["no_systems_found"]) | |
| st.stop() | |
| df.columns = [ | |
| "Name", "Leistung", "Investitionskosten", "Betriebsdauer", "Effizienz", "Emissionen", | |
| "Preisänderungsfaktor_Inv", "Betriebskosten", "Preisänderungsfaktor_Bedarf", | |
| "Fixkosten_O+M", "Preisänderungsfaktor_O+M", "Emissionsänderungsfaktor", "Förderung" | |
| ] | |
| df = apply_technology_name_language(df,ui) | |
| for col in df.columns[2:]: | |
| df[col] = df[col].astype(str).str.replace(",", ".").str.replace("|", ".") | |
| df[col] = pd.to_numeric(df[col], errors='coerce') | |
| st.session_state.df_heizsysteme = df.copy() | |
| st.session_state.user_values = {} | |
| st.session_state.input_values = { | |
| "floor_area": floor_area, | |
| "year_built": year_built, | |
| "specific_energy_demand": specific_energy_demand, | |
| "interest_rate": interest_rate, | |
| "observation_period": observation_period, | |
| "emission_price_change_factor": emission_price_change_factor, | |
| "emission_cost": emission_cost | |
| } | |
| except Exception as e: | |
| st.error(ui["output"]["system_selection_error"].format(error=e)) | |
| st.stop() | |
| else: | |
| df = st.session_state.df_heizsysteme.copy() | |
| inputs = st.session_state.input_values | |
| floor_area = inputs["floor_area"] | |
| year_built = inputs["year_built"] | |
| specific_energy_demand = inputs["specific_energy_demand"] | |
| interest_rate = inputs["interest_rate"] | |
| observation_period = inputs["observation_period"] | |
| emission_price_change_factor = inputs["emission_price_change_factor"] | |
| emission_cost = inputs["emission_cost"] | |
| return df, floor_area, year_built, specific_energy_demand, interest_rate, observation_period, emission_price_change_factor, emission_cost | |
| def generate_preview_df(df_input_row, scenario_id): | |
| try: | |
| # Zugriff jetzt mit festen internen Spaltennamen, NICHT über ui["batch"]["columns"] | |
| floor_area = parsefloat(df_input_row["floor_area"]) | |
| year_built = int(df_input_row["year_built"]) | |
| total_demand = parsefloat(df_input_row.get("heat_demand", "")) | |
| specific_demand = parsefloat(df_input_row.get("specific_demand", "")) | |
| # Heizwärmebedarf berechnen | |
| if total_demand and total_demand > 0 and floor_area and floor_area > 0: | |
| demand_specific = total_demand / floor_area | |
| elif specific_demand and specific_demand > 0: | |
| demand_specific = specific_demand | |
| else: | |
| raise ValueError("preview_error: Angaben zum Wärmebedarf fehlen oder ungültig.") | |
| # Heizsysteme auswählen | |
| df = find_suitable_heating_systems(demand_specific, year_built, floor_area, scenario_id) | |
| # Spalten für Heizsystem-DF fixieren (interne Namen) | |
| df.columns = [ | |
| "Name", "Leistung", "Investitionskosten", "Betriebsdauer", "Effizienz", "Emissionen", | |
| "Preisänderungsfaktor_Inv", "Betriebskosten", "Preisänderungsfaktor_Bedarf", | |
| "Fixkosten_O+M", "Preisänderungsfaktor_O+M", "Emissionsänderungsfaktor", "Förderung" | |
| ] | |
| # Numerische Spalten bereinigen | |
| for col in df.columns[2:]: | |
| df[col] = df[col].astype(str).str.replace(",", ".").str.replace("|", ".") | |
| df[col] = pd.to_numeric(df[col], errors="coerce") | |
| return df | |
| except Exception as e: | |
| raise RuntimeError(str(e)) | |
| def prepare_heating_system_df(specific_energy_demand, year_built, floor_area, scen_id, heat_load_user=None): | |
| df = find_suitable_heating_systems(specific_energy_demand, year_built, floor_area, scen_id, heat_load_user=heat_load_user) | |
| df.columns = [ | |
| "Name", "Leistung", "Investitionskosten", "Betriebsdauer", "Effizienz", "Emissionen", | |
| "Preisänderungsfaktor_Inv", "Betriebskosten", "Preisänderungsfaktor_Bedarf", | |
| "Fixkosten_O+M", "Preisänderungsfaktor_O+M", "Emissionsänderungsfaktor", "Förderung" | |
| ] | |
| for col in df.columns[2:]: | |
| df[col] = df[col].astype(str).str.replace(",", ".").str.replace("|", ".") | |
| df[col] = pd.to_numeric(df[col], errors='coerce') | |
| return df |