HeatTransPlan / frontend /src /utils /streamUtils.ts
drzg15's picture
Initial code commit with LFS for binaries
c993983
/**
* Pure utility to extract stream info — direct port of the Python
* get_stream_info() from potential_analysis.py (lines 2289-2418).
*/
import type { Stream } from '../types/stream';
import type { StreamInfo } from '../types/analysis';
function toFloat(v: unknown): number | null {
if (v === null || v === undefined || v === '') return null;
const n = Number(v);
return Number.isFinite(n) ? n : null;
}
export function getStreamInfo(stream: Stream): StreamInfo {
const sv = stream.stream_values ?? {};
const properties = stream.properties ?? {};
const values = stream.values ?? {};
let tin: number | null = null;
let tout: number | null = null;
let mdot: number | null = null;
let cpVal: number | null = null;
let cpDirect: number | null = null;
// 1. Try stream_values (new structure)
if (sv) {
tin = toFloat(sv['Tin']);
tout = toFloat(sv['Tout']);
mdot = toFloat(sv['ṁ']);
cpVal = toFloat(sv['cp']);
cpDirect = toFloat(sv['CP']);
}
// 2. Check properties/values dict structure
if (properties && values) {
for (const [pk, pname] of Object.entries(properties)) {
const vk = pk.replace('prop', 'val');
const v = (values as Record<string, string>)[vk] ?? '';
if (pname === 'Tin' && v && tin === null) tin = toFloat(v);
else if (pname === 'Tout' && v && tout === null) tout = toFloat(v);
else if (pname === 'ṁ' && v && mdot === null) mdot = toFloat(v);
else if (pname === 'cp' && v && cpVal === null) cpVal = toFloat(v);
else if (pname === 'CP' && v && cpDirect === null) cpDirect = toFloat(v);
}
}
// 3. Fallback to legacy fields
if (tin === null && stream.temp_in) tin = toFloat(stream.temp_in);
if (tout === null && stream.temp_out) tout = toFloat(stream.temp_out);
if (mdot === null && stream.mdot) mdot = toFloat(stream.mdot);
if (cpVal === null && stream.cp) cpVal = toFloat(stream.cp);
// Determine stream type
let type: StreamInfo['type'] = null;
if (tin !== null && tout !== null) {
type = tin > tout ? 'Hot stream (Heat Source)' : 'Cold stream (Heat sink)';
}
// CP: use direct if provided, otherwise mdot * cp
let CP: number | null = null;
if (cpDirect !== null) {
CP = cpDirect;
} else if (mdot !== null && cpVal !== null) {
CP = mdot * cpVal;
}
// Q = |CP * (Tout - Tin)|
let Q: number | null = null;
if (CP !== null && tin !== null && tout !== null) {
Q = Math.abs(CP * (tout - tin));
}
return { tin, tout, mdot, cp: cpVal, CP, Q, type };
}