Spaces:
Running
Running
working adding the demands
Browse files- src/pages/potential_analysis.py +167 -120
src/pages/potential_analysis.py
CHANGED
|
@@ -2074,147 +2074,194 @@ with button_col:
|
|
| 2074 |
# Initialize session state for selections if not exists
|
| 2075 |
if 'selected_items' not in st.session_state:
|
| 2076 |
st.session_state['selected_items'] = {}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2077 |
|
| 2078 |
-
#
|
| 2079 |
-
|
| 2080 |
-
|
| 2081 |
-
|
| 2082 |
-
|
| 2083 |
-
|
| 2084 |
-
|
| 2085 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2086 |
|
| 2087 |
-
#
|
| 2088 |
-
|
| 2089 |
-
|
| 2090 |
-
|
| 2091 |
-
|
| 2092 |
-
|
| 2093 |
-
|
| 2094 |
-
values = stream.get('values', {})
|
| 2095 |
-
|
| 2096 |
-
# Also check stream_values (new structure)
|
| 2097 |
-
stream_values = stream.get('stream_values', {})
|
| 2098 |
-
if not stream_values:
|
| 2099 |
-
stream_values = stream.get('product_values', {})
|
| 2100 |
-
|
| 2101 |
-
tin = None
|
| 2102 |
-
tout = None
|
| 2103 |
-
mdot = None
|
| 2104 |
-
cp_val = None
|
| 2105 |
-
CP_direct = None # CP provided directly
|
| 2106 |
-
|
| 2107 |
-
# First try stream_values (new structure)
|
| 2108 |
-
if stream_values:
|
| 2109 |
-
if 'Tin' in stream_values and stream_values['Tin']:
|
| 2110 |
try:
|
| 2111 |
-
tin = float(
|
| 2112 |
except (ValueError, TypeError):
|
| 2113 |
pass
|
| 2114 |
-
|
| 2115 |
try:
|
| 2116 |
-
tout = float(
|
| 2117 |
except (ValueError, TypeError):
|
| 2118 |
pass
|
| 2119 |
-
|
| 2120 |
try:
|
| 2121 |
-
mdot = float(
|
| 2122 |
except (ValueError, TypeError):
|
| 2123 |
pass
|
| 2124 |
-
|
| 2125 |
try:
|
| 2126 |
-
cp_val = float(
|
| 2127 |
except (ValueError, TypeError):
|
| 2128 |
pass
|
| 2129 |
-
|
| 2130 |
try:
|
| 2131 |
-
CP_direct = float(
|
| 2132 |
except (ValueError, TypeError):
|
| 2133 |
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2134 |
|
| 2135 |
-
#
|
| 2136 |
-
|
| 2137 |
-
for pk, pname in properties.items():
|
| 2138 |
-
vk = pk.replace('prop', 'val')
|
| 2139 |
-
v = values.get(vk, '')
|
| 2140 |
-
|
| 2141 |
-
if pname == 'Tin' and v and tin is None:
|
| 2142 |
-
try:
|
| 2143 |
-
tin = float(v)
|
| 2144 |
-
except (ValueError, TypeError):
|
| 2145 |
-
pass
|
| 2146 |
-
elif pname == 'Tout' and v and tout is None:
|
| 2147 |
-
try:
|
| 2148 |
-
tout = float(v)
|
| 2149 |
-
except (ValueError, TypeError):
|
| 2150 |
-
pass
|
| 2151 |
-
elif pname == 'ṁ' and v and mdot is None:
|
| 2152 |
-
try:
|
| 2153 |
-
mdot = float(v)
|
| 2154 |
-
except (ValueError, TypeError):
|
| 2155 |
-
pass
|
| 2156 |
-
elif pname == 'cp' and v and cp_val is None:
|
| 2157 |
-
try:
|
| 2158 |
-
cp_val = float(v)
|
| 2159 |
-
except (ValueError, TypeError):
|
| 2160 |
-
pass
|
| 2161 |
-
elif pname == 'CP' and v and CP_direct is None:
|
| 2162 |
-
try:
|
| 2163 |
-
CP_direct = float(v)
|
| 2164 |
-
except (ValueError, TypeError):
|
| 2165 |
-
pass
|
| 2166 |
-
|
| 2167 |
-
# Fallback to legacy fields
|
| 2168 |
-
if tin is None and stream.get('temp_in'):
|
| 2169 |
-
try:
|
| 2170 |
-
tin = float(stream['temp_in'])
|
| 2171 |
-
except (ValueError, TypeError):
|
| 2172 |
-
pass
|
| 2173 |
-
if tout is None and stream.get('temp_out'):
|
| 2174 |
-
try:
|
| 2175 |
-
tout = float(stream['temp_out'])
|
| 2176 |
-
except (ValueError, TypeError):
|
| 2177 |
-
pass
|
| 2178 |
-
if mdot is None and stream.get('mdot'):
|
| 2179 |
-
try:
|
| 2180 |
-
mdot = float(stream['mdot'])
|
| 2181 |
-
except (ValueError, TypeError):
|
| 2182 |
-
pass
|
| 2183 |
-
if cp_val is None and stream.get('cp'):
|
| 2184 |
-
try:
|
| 2185 |
-
cp_val = float(stream['cp'])
|
| 2186 |
-
except (ValueError, TypeError):
|
| 2187 |
-
pass
|
| 2188 |
-
|
| 2189 |
-
# Determine stream type
|
| 2190 |
-
stream_type = None
|
| 2191 |
-
if tin is not None and tout is not None:
|
| 2192 |
-
if tin > tout:
|
| 2193 |
-
stream_type = "Hot stream (Heat Source)"
|
| 2194 |
-
else:
|
| 2195 |
-
stream_type = "Cold stream (Heat sink)"
|
| 2196 |
|
| 2197 |
-
#
|
| 2198 |
-
|
| 2199 |
-
|
| 2200 |
-
|
| 2201 |
-
|
| 2202 |
-
|
|
|
|
|
|
|
|
|
|
| 2203 |
|
| 2204 |
-
#
|
| 2205 |
-
|
| 2206 |
-
|
| 2207 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2208 |
|
| 2209 |
-
|
| 2210 |
-
|
| 2211 |
-
|
| 2212 |
-
|
| 2213 |
-
|
| 2214 |
-
|
| 2215 |
-
|
| 2216 |
-
'type': stream_type
|
| 2217 |
-
}
|
| 2218 |
|
| 2219 |
# Left column: Display streams with selection checkboxes
|
| 2220 |
with streams_col:
|
|
|
|
| 2074 |
# Initialize session state for selections if not exists
|
| 2075 |
if 'selected_items' not in st.session_state:
|
| 2076 |
st.session_state['selected_items'] = {}
|
| 2077 |
+
if 'current_heat_demand' not in st.session_state:
|
| 2078 |
+
st.session_state['current_heat_demand'] = 0.0
|
| 2079 |
+
if 'current_cooling_demand' not in st.session_state:
|
| 2080 |
+
st.session_state['current_cooling_demand'] = 0.0
|
| 2081 |
|
| 2082 |
+
# Helper function to determine stream type and extract data
|
| 2083 |
+
def get_stream_info(stream):
|
| 2084 |
+
"""Extract Tin, Tout, mdot, cp, CP from stream and determine if Hot stream (Heat Source) or Cold Stream (Heat Sink).
|
| 2085 |
+
Calculate Q = CP * (Tout - Tin).
|
| 2086 |
+
CP can be provided directly, or calculated as mdot * cp.
|
| 2087 |
+
"""
|
| 2088 |
+
properties = stream.get('properties', {})
|
| 2089 |
+
values = stream.get('values', {})
|
| 2090 |
+
|
| 2091 |
+
# Also check stream_values (new structure)
|
| 2092 |
+
stream_values = stream.get('stream_values', {})
|
| 2093 |
+
if not stream_values:
|
| 2094 |
+
stream_values = stream.get('product_values', {})
|
| 2095 |
+
|
| 2096 |
+
tin = None
|
| 2097 |
+
tout = None
|
| 2098 |
+
mdot = None
|
| 2099 |
+
cp_val = None
|
| 2100 |
+
CP_direct = None # CP provided directly
|
| 2101 |
+
|
| 2102 |
+
# First try stream_values (new structure)
|
| 2103 |
+
if stream_values:
|
| 2104 |
+
if 'Tin' in stream_values and stream_values['Tin']:
|
| 2105 |
+
try:
|
| 2106 |
+
tin = float(stream_values['Tin'])
|
| 2107 |
+
except (ValueError, TypeError):
|
| 2108 |
+
pass
|
| 2109 |
+
if 'Tout' in stream_values and stream_values['Tout']:
|
| 2110 |
+
try:
|
| 2111 |
+
tout = float(stream_values['Tout'])
|
| 2112 |
+
except (ValueError, TypeError):
|
| 2113 |
+
pass
|
| 2114 |
+
if 'ṁ' in stream_values and stream_values['ṁ']:
|
| 2115 |
+
try:
|
| 2116 |
+
mdot = float(stream_values['ṁ'])
|
| 2117 |
+
except (ValueError, TypeError):
|
| 2118 |
+
pass
|
| 2119 |
+
if 'cp' in stream_values and stream_values['cp']:
|
| 2120 |
+
try:
|
| 2121 |
+
cp_val = float(stream_values['cp'])
|
| 2122 |
+
except (ValueError, TypeError):
|
| 2123 |
+
pass
|
| 2124 |
+
if 'CP' in stream_values and stream_values['CP']:
|
| 2125 |
+
try:
|
| 2126 |
+
CP_direct = float(stream_values['CP'])
|
| 2127 |
+
except (ValueError, TypeError):
|
| 2128 |
+
pass
|
| 2129 |
|
| 2130 |
+
# Check properties dict structure
|
| 2131 |
+
if isinstance(properties, dict) and isinstance(values, dict):
|
| 2132 |
+
for pk, pname in properties.items():
|
| 2133 |
+
vk = pk.replace('prop', 'val')
|
| 2134 |
+
v = values.get(vk, '')
|
| 2135 |
+
|
| 2136 |
+
if pname == 'Tin' and v and tin is None:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2137 |
try:
|
| 2138 |
+
tin = float(v)
|
| 2139 |
except (ValueError, TypeError):
|
| 2140 |
pass
|
| 2141 |
+
elif pname == 'Tout' and v and tout is None:
|
| 2142 |
try:
|
| 2143 |
+
tout = float(v)
|
| 2144 |
except (ValueError, TypeError):
|
| 2145 |
pass
|
| 2146 |
+
elif pname == 'ṁ' and v and mdot is None:
|
| 2147 |
try:
|
| 2148 |
+
mdot = float(v)
|
| 2149 |
except (ValueError, TypeError):
|
| 2150 |
pass
|
| 2151 |
+
elif pname == 'cp' and v and cp_val is None:
|
| 2152 |
try:
|
| 2153 |
+
cp_val = float(v)
|
| 2154 |
except (ValueError, TypeError):
|
| 2155 |
pass
|
| 2156 |
+
elif pname == 'CP' and v and CP_direct is None:
|
| 2157 |
try:
|
| 2158 |
+
CP_direct = float(v)
|
| 2159 |
except (ValueError, TypeError):
|
| 2160 |
pass
|
| 2161 |
+
|
| 2162 |
+
# Fallback to legacy fields
|
| 2163 |
+
if tin is None and stream.get('temp_in'):
|
| 2164 |
+
try:
|
| 2165 |
+
tin = float(stream['temp_in'])
|
| 2166 |
+
except (ValueError, TypeError):
|
| 2167 |
+
pass
|
| 2168 |
+
if tout is None and stream.get('temp_out'):
|
| 2169 |
+
try:
|
| 2170 |
+
tout = float(stream['temp_out'])
|
| 2171 |
+
except (ValueError, TypeError):
|
| 2172 |
+
pass
|
| 2173 |
+
if mdot is None and stream.get('mdot'):
|
| 2174 |
+
try:
|
| 2175 |
+
mdot = float(stream['mdot'])
|
| 2176 |
+
except (ValueError, TypeError):
|
| 2177 |
+
pass
|
| 2178 |
+
if cp_val is None and stream.get('cp'):
|
| 2179 |
+
try:
|
| 2180 |
+
cp_val = float(stream['cp'])
|
| 2181 |
+
except (ValueError, TypeError):
|
| 2182 |
+
pass
|
| 2183 |
+
|
| 2184 |
+
# Determine stream type
|
| 2185 |
+
stream_type = None
|
| 2186 |
+
if tin is not None and tout is not None:
|
| 2187 |
+
if tin > tout:
|
| 2188 |
+
stream_type = "Hot stream (Heat Source)"
|
| 2189 |
+
else:
|
| 2190 |
+
stream_type = "Cold stream (Heat sink)"
|
| 2191 |
+
|
| 2192 |
+
# Determine CP: use direct CP if provided, otherwise calculate from mdot * cp
|
| 2193 |
+
CP_flow = None
|
| 2194 |
+
if CP_direct is not None:
|
| 2195 |
+
CP_flow = CP_direct
|
| 2196 |
+
elif mdot is not None and cp_val is not None:
|
| 2197 |
+
CP_flow = mdot * cp_val
|
| 2198 |
+
|
| 2199 |
+
# Calculate Q = CP * |Tout - Tin| (always positive)
|
| 2200 |
+
Q = None
|
| 2201 |
+
if CP_flow is not None and tin is not None and tout is not None:
|
| 2202 |
+
Q = abs(CP_flow * (tout - tin))
|
| 2203 |
+
|
| 2204 |
+
return {
|
| 2205 |
+
'tin': tin,
|
| 2206 |
+
'tout': tout,
|
| 2207 |
+
'mdot': mdot,
|
| 2208 |
+
'cp': cp_val,
|
| 2209 |
+
'CP': CP_flow,
|
| 2210 |
+
'Q': Q,
|
| 2211 |
+
'type': stream_type
|
| 2212 |
+
}
|
| 2213 |
+
|
| 2214 |
+
# Get processes from session state
|
| 2215 |
+
processes = st.session_state.get('processes', [])
|
| 2216 |
+
|
| 2217 |
+
# Current Demands Section
|
| 2218 |
+
with st.expander("Current Energy Demands (They can be added to calculate the improvement with respect to the status quo)", expanded=False):
|
| 2219 |
+
heat_demand = st.number_input("Heat Demand (kW)", min_value=0.0, step=0.1, value=st.session_state.get('current_heat_demand', 0.0))
|
| 2220 |
+
cooling_demand = st.number_input("Cooling Demand (kW)", min_value=0.0, step=0.1, value=st.session_state.get('current_cooling_demand', 0.0))
|
| 2221 |
+
|
| 2222 |
+
# Create stream options
|
| 2223 |
+
stream_options = []
|
| 2224 |
+
for idx, process in enumerate(processes):
|
| 2225 |
+
for stream_idx, stream in enumerate(process.get('streams', [])):
|
| 2226 |
+
stream_name = stream.get('name', f'Stream {stream_idx + 1} in {process.get('name', f'Subprocess {idx + 1}')}')
|
| 2227 |
+
stream_options.append((idx, stream_idx, stream_name))
|
| 2228 |
+
|
| 2229 |
+
selected_stream_names = st.multiselect("Streams", [name for _, _, name in stream_options], default=[name for _, _, name in stream_options])
|
| 2230 |
+
|
| 2231 |
+
if st.button("Apply Demands"):
|
| 2232 |
+
st.session_state['current_heat_demand'] = heat_demand
|
| 2233 |
+
st.session_state['current_cooling_demand'] = cooling_demand
|
| 2234 |
|
| 2235 |
+
# Get selected stream indices
|
| 2236 |
+
selected_stream_indices = [(idx, sidx) for idx, sidx, name in stream_options if name in selected_stream_names]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2237 |
|
| 2238 |
+
# For cooling demand, select all hot streams from selected streams
|
| 2239 |
+
if cooling_demand > 0:
|
| 2240 |
+
for proc_idx, stream_idx in selected_stream_indices:
|
| 2241 |
+
process = processes[proc_idx]
|
| 2242 |
+
stream = process.get('streams', [])[stream_idx]
|
| 2243 |
+
info = get_stream_info(stream)
|
| 2244 |
+
if info['type'] == "Hot stream (Heat Source)":
|
| 2245 |
+
stream_key = f"stream_{proc_idx}_{stream_idx}"
|
| 2246 |
+
st.session_state['selected_items'][stream_key] = True
|
| 2247 |
|
| 2248 |
+
# For heating demand, select all cold streams from selected streams
|
| 2249 |
+
if heat_demand > 0:
|
| 2250 |
+
for proc_idx, stream_idx in selected_stream_indices:
|
| 2251 |
+
process = processes[proc_idx]
|
| 2252 |
+
stream = process.get('streams', [])[stream_idx]
|
| 2253 |
+
info = get_stream_info(stream)
|
| 2254 |
+
if info['type'] == "Cold stream (Heat sink)":
|
| 2255 |
+
stream_key = f"stream_{proc_idx}_{stream_idx}"
|
| 2256 |
+
st.session_state['selected_items'][stream_key] = True
|
| 2257 |
|
| 2258 |
+
st.success("Demands applied and streams selected.")
|
| 2259 |
+
|
| 2260 |
+
if not processes:
|
| 2261 |
+
st.info("No processes found. Please add processes in the Data Collection page first.")
|
| 2262 |
+
else:
|
| 2263 |
+
# Create side-by-side layout: streams on left, map on right
|
| 2264 |
+
streams_col, map_col = st.columns([1, 1])
|
|
|
|
|
|
|
| 2265 |
|
| 2266 |
# Left column: Display streams with selection checkboxes
|
| 2267 |
with streams_col:
|