Some checks failed
CI / check (push) Has been cancelled
Checkpoint incomplete calibration work (cond SDT green, evap SST failing) plus related solver/UI changes so the next pass can fix and extend safely. Co-authored-by: Cursor <cursoragent@cursor.com>
1976 lines
80 KiB
TypeScript
1976 lines
80 KiB
TypeScript
/**
|
||
* Entropyk component catalogue.
|
||
*
|
||
* Mirrors the backend `/api/components` endpoint. Each entry defines:
|
||
* - type: CLI JSON "type" string (matches crates/cli/src/run.rs create_component)
|
||
* - label: human-readable name shown in the palette and node
|
||
* - category: palette grouping
|
||
* - ports: ordered port names (inlet/outlet/suction/discharge/...)
|
||
* — used to place React Flow handles.
|
||
* - color: hex colour for the node header
|
||
* - params: editable parameters with type, unit, default, required flag
|
||
*/
|
||
|
||
export type ParamKind = "number" | "string" | "boolean";
|
||
|
||
export interface ParamMeta {
|
||
key: string;
|
||
label: string;
|
||
kind: ParamKind;
|
||
unit?: string;
|
||
default?: number | string | boolean;
|
||
required?: boolean;
|
||
section?: string;
|
||
description?: string;
|
||
min?: number;
|
||
max?: number;
|
||
step?: number;
|
||
options?: Array<{ value: string | number; label: string }>;
|
||
advanced?: boolean;
|
||
/**
|
||
* Dymola/EES-style Fixed checkbox.
|
||
* Fixed ON = value imposed (parameter or measured target).
|
||
* Fixed OFF = free for the solver (calibration tuner / free unknown).
|
||
*/
|
||
fixable?: boolean;
|
||
/** Default for the Fixed checkbox when `fixable` (true = Fixed). */
|
||
defaultFixed?: boolean;
|
||
/**
|
||
* When Fixed ON: use this param value as a control setpoint for the named
|
||
* measure output (e.g. `saturationTemperature`, `superheat`).
|
||
*/
|
||
measureOutput?: string;
|
||
/**
|
||
* When Fixed OFF: free this actuator/calibration factor (e.g. `z_ua`).
|
||
* Requires a Fixed measure on the same component to stay DoF-balanced.
|
||
*/
|
||
actuatorFactor?: string;
|
||
/** Bounds used when the factor is free (actuator min/max). */
|
||
freeMin?: number;
|
||
freeMax?: number;
|
||
/**
|
||
* Whether this param can be picked as a Multi-run sweep axis.
|
||
* Source of truth for sweepability — replaces the old hardcoded whitelist.
|
||
*/
|
||
sweepable?: boolean;
|
||
/** Multi-run optgroup for the param (only meaningful when `sweepable`). */
|
||
sweepGroup?: "boundaries" | "thermal" | "machine" | "global";
|
||
}
|
||
|
||
/** Internal params key prefix for Fixed flags (not sent as component fields). */
|
||
export const FIXED_FLAG_PREFIX = "__fixed_";
|
||
|
||
export function fixedFlagKey(paramKey: string): string {
|
||
return `${FIXED_FLAG_PREFIX}${paramKey}`;
|
||
}
|
||
|
||
/** Whether a param is Fixed (default = defaultFixed ?? true). */
|
||
export function isParamFixed(
|
||
params: Record<string, number | string | boolean | undefined>,
|
||
meta: ParamMeta,
|
||
): boolean {
|
||
if (!meta.fixable) return true;
|
||
const flag = params[fixedFlagKey(meta.key)];
|
||
if (flag === true || flag === "true") return true;
|
||
if (flag === false || flag === "false") return false;
|
||
return meta.defaultFixed !== false;
|
||
}
|
||
|
||
export interface ComponentMeta {
|
||
type: string;
|
||
label: string;
|
||
category: string;
|
||
/** Short purpose shown under the component title (plain language). */
|
||
description: string;
|
||
/**
|
||
* Contextual help (French) shown in the Help panel.
|
||
* Explain when to use it, main ports, and typical Fixed/Free usage.
|
||
*/
|
||
help?: string;
|
||
/** Doc file under docs/components/ (without path), e.g. "flooded-evaporator". */
|
||
docSlug?: string;
|
||
ports: string[];
|
||
color: string;
|
||
params: ParamMeta[];
|
||
}
|
||
|
||
export function genericMeta(type?: string): ComponentMeta {
|
||
const cleanType = String(type || "GenericComponent");
|
||
return {
|
||
type: cleanType,
|
||
label: cleanType,
|
||
category: "Generic",
|
||
description: `Composant thermodynamique (${cleanType})`,
|
||
ports: ["inlet", "outlet"],
|
||
color: "#64748b",
|
||
params: [],
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Port side on the node: "inlet"-like ports go on the left, "outlet"-like
|
||
* ports on the right. Economizer / liquid_outlet sit on the top/bottom.
|
||
*/
|
||
export function portSide(port: string): "left" | "right" | "top" | "bottom" {
|
||
const p = String(port || "");
|
||
if (p === "secondary_inlet") return "bottom";
|
||
if (p === "secondary_outlet") return "top";
|
||
if (p === "hot_inlet" || p === "cold_inlet") return "left";
|
||
if (p === "hot_outlet" || p === "cold_outlet") return "right";
|
||
if (p.startsWith("outlet")) return "right";
|
||
if (p === "discharge") return "right";
|
||
if (p === "liquid_outlet" || p === "vapor_outlet") return "bottom";
|
||
if (p.startsWith("inlet")) return "left";
|
||
if (p === "suction") return "left";
|
||
if (p === "economizer") return "top";
|
||
return "left";
|
||
}
|
||
|
||
/** True for the secondary (heat-transfer fluid / caloporteur) ports of an exchanger. */
|
||
export function isSecondaryPort(port: string): boolean {
|
||
const p = String(port || "");
|
||
return p === "secondary_inlet" || p === "secondary_outlet";
|
||
}
|
||
|
||
/**
|
||
* Whether a port emits flow (source) or receives it (target).
|
||
* Flow in a P&ID is directional: a connection is dragged from a source
|
||
* (outlet/discharge) to a target (inlet/suction).
|
||
*/
|
||
export function portRole(port: string): "source" | "target" {
|
||
const p = String(port || "");
|
||
if (
|
||
p.startsWith("outlet") ||
|
||
p === "discharge" ||
|
||
p === "liquid_outlet" ||
|
||
p === "vapor_outlet" ||
|
||
p.endsWith("_outlet")
|
||
) {
|
||
return "source";
|
||
}
|
||
return "target";
|
||
}
|
||
|
||
/**
|
||
* Per-family node footprint (px), Dymola-style: a heat exchanger is a wide
|
||
* vessel, a separator is a tall column, a pipe is a long thin run, a valve is
|
||
* compact. Size encodes what the part is, not just decoration.
|
||
*/
|
||
export function nodeSize(type: string): { w: number; h: number } {
|
||
const t = String(type || "");
|
||
if (t === "Probe") return { w: 36, h: 36 };
|
||
if (t === "SaturatedController") return { w: 184, h: 96 };
|
||
if (t.includes("Compressor")) return { w: 76, h: 76 };
|
||
if (t === "HeatExchanger") return { w: 92, h: 92 };
|
||
// Flooded is a horizontal drum; plate a tall pack; coils wide batteries.
|
||
if (t.includes("Flooded")) return { w: 128, h: 92 };
|
||
if (t.includes("Bphx")) return { w: 80, h: 110 };
|
||
if (t.includes("FinCoil") || t.includes("AirCooled") || t.includes("Mchx"))
|
||
return { w: 126, h: 88 };
|
||
if (t.includes("Condenser") || t.includes("Evaporator")) return { w: 126, h: 88 };
|
||
if (t.includes("Valve")) return { w: 56, h: 56 };
|
||
if (t === "Pump" || t === "Fan") return { w: 72, h: 72 };
|
||
if (t === "Pipe" || t.includes("Pipe") || t === "AirDuct") return { w: 118, h: 42 };
|
||
if (t === "Drum") return { w: 58, h: 108 };
|
||
if (t === "FlowSplitter" || t === "FlowMerger") return { w: 72, h: 64 };
|
||
if (t.endsWith("Source") || t.endsWith("Sink")) return { w: 62, h: 56 };
|
||
return { w: 88, h: 58 };
|
||
}
|
||
|
||
/** Short label shown next to a handle on the node. */
|
||
export function portLabel(port: string): string {
|
||
const map: Record<string, string> = {
|
||
inlet: "in",
|
||
outlet: "out",
|
||
suction: "suc",
|
||
discharge: "dis",
|
||
economizer: "eco",
|
||
liquid_outlet: "liq",
|
||
vapor_outlet: "vap",
|
||
outlet_a: "A",
|
||
outlet_b: "B",
|
||
inlet_a: "A",
|
||
inlet_b: "B",
|
||
hot_inlet: "h·in",
|
||
hot_outlet: "h·out",
|
||
cold_inlet: "c·in",
|
||
cold_outlet: "c·out",
|
||
secondary_inlet: "htf·in",
|
||
secondary_outlet: "htf·out",
|
||
};
|
||
return map[port] ?? port;
|
||
}
|
||
|
||
export const COMPONENT_CATEGORIES = [
|
||
"Compressors",
|
||
"Heat Exchangers",
|
||
"Expansion",
|
||
"Piping",
|
||
"Hydraulics",
|
||
"Boundaries",
|
||
"Instrumentation",
|
||
"Advanced",
|
||
"Generic",
|
||
] as const;
|
||
|
||
export const COMPONENTS: ComponentMeta[] = [
|
||
// ── Instrumentation: measurement taps for calibration (Probe = all measurements) ──
|
||
{
|
||
type: "Probe",
|
||
label: "Probe (sonde)",
|
||
category: "Instrumentation",
|
||
description:
|
||
"Sonde de mesure posée sur une ligne. Lit P/T/SH/SC/SST/SDT/DGT/DSH/capacité/ṁ/h à cet endroit. Toute calibration impose sa cible sur un Probe.",
|
||
help:
|
||
"Sonde de calibration (Probe)\n" +
|
||
"Toute calibration se fait via un Probe posé sur une ligne (règle dure).\n\n" +
|
||
"1. Glisse le Probe sur un fil du schéma (comme pour insérer un Pipe).\n" +
|
||
"2. Choisis la grandeur mesurée (SST, SDT, DGT, DSH, SH, SC, T, P, débit, capacité, enthalpie) et le fluide.\n" +
|
||
"3. Coche Fixed sur « Cible » et tape la valeur mesurée.\n" +
|
||
"4. Libère le Z-factor correspondant (Z_UA, Z_dP, Z_flow…) sur le composant à calibrer.\n" +
|
||
"Le solveur appaire automatiquement le Probe (mesure) et le Z-factor libre (inconnue).",
|
||
ports: ["inlet", "outlet"],
|
||
color: "#0ea5e9",
|
||
params: [
|
||
{
|
||
key: "measure",
|
||
label: "Grandeur mesurée",
|
||
kind: "string",
|
||
default: "SH",
|
||
required: true,
|
||
section: "Mesure",
|
||
description:
|
||
"Grandeur physique mesurée à l'emplacement du Probe. SST/SDT = Tsat(P), SH/DSH = T−Tsat(P), SC = Tsat(P)−T.",
|
||
options: [
|
||
{ value: "SST", label: "SST (Tsat aspiration)" },
|
||
{ value: "SDT", label: "SDT (Tsat refoulement)" },
|
||
{ value: "DGT", label: "DGT (T° gaz refoulement)" },
|
||
{ value: "DSH", label: "DSH (surch. refoulement)" },
|
||
{ value: "SH", label: "SH (surchauffe)" },
|
||
{ value: "SC", label: "SC (sous-refroid.)" },
|
||
{ value: "T", label: "T (température)" },
|
||
{ value: "P", label: "P (pression)" },
|
||
{ value: "MassFlow", label: "Débit massique" },
|
||
{ value: "Capacity", label: "Capacité (kW)" },
|
||
{ value: "Enthalpy", label: "Enthalpie" },
|
||
],
|
||
},
|
||
{
|
||
key: "fluid",
|
||
label: "Fluide",
|
||
kind: "string",
|
||
default: "R134a",
|
||
required: true,
|
||
section: "Mesure",
|
||
description: "Fluide frigorigène pour le calcul de Tsat/SH/SC (via CoolProp).",
|
||
},
|
||
{
|
||
key: "target",
|
||
label: "Cible (Fixed = impose)",
|
||
kind: "number",
|
||
section: "Calibration",
|
||
fixable: true,
|
||
defaultFixed: false,
|
||
// Auto: resolved from `measure` at config-build time
|
||
// (SST/SDT → saturationTemperature, SH/DSH → superheat, SC → subcooling,
|
||
// DGT/T → temperature, P → pressure, MassFlow → massFlowRate,
|
||
// Capacity → capacity, Enthalpy → heatTransferRate as carrier).
|
||
measureOutput: "auto",
|
||
description:
|
||
"Coche Fixed et tape la valeur mesurée (K pour températures, K pour SH/SC, Pa pour P, kg/s pour débit, W pour capacité, J/kg pour h).",
|
||
},
|
||
],
|
||
},
|
||
|
||
// ── Advanced regulation (optional — most users use Fixed on Calibration tab) ──
|
||
{
|
||
type: "SaturatedController",
|
||
label: "Regulation loop (advanced)",
|
||
category: "Advanced",
|
||
description:
|
||
"Optional. Links a measured quantity (e.g. superheat) to a free actuator (e.g. valve opening). For simple calibration (SST + Z_UA), prefer the Calibration tab Fixed checkboxes — you do not need this block.",
|
||
help:
|
||
"À quoi ça sert ?\n" +
|
||
"• Boucle de régulation avancée : tu imposes une grandeur mesurée et tu libères un actionneur.\n" +
|
||
"• Exemple : superheat mesuré → ouverture EXV libre.\n\n" +
|
||
"Quand NE PAS l’utiliser ?\n" +
|
||
"• Pour calibrer Z_UA sur une SST : utilise l’onglet Calibration du composant (cases Fixed).\n" +
|
||
"• Ce bloc est pour les cas multi-objectifs / priorités (override chain).\n\n" +
|
||
"Ce n’est pas un composant thermodynamique : il n’a pas de ports fluide.",
|
||
docSlug: undefined,
|
||
ports: [],
|
||
color: "#7c3aed",
|
||
params: [
|
||
{
|
||
key: "measure_component",
|
||
label: "Composant mesuré",
|
||
kind: "string",
|
||
default: "evap",
|
||
required: true,
|
||
section: "Mesure (imposé)",
|
||
description: "Nom du composant dont on lit la grandeur (ex. evap).",
|
||
},
|
||
{
|
||
key: "measure_output",
|
||
label: "Grandeur mesurée",
|
||
kind: "string",
|
||
default: "saturationTemperature",
|
||
required: true,
|
||
section: "Mesure (imposé)",
|
||
description: "Ex. saturationTemperature (SST/SDT), superheat, capacity…",
|
||
},
|
||
{
|
||
key: "target",
|
||
label: "Consigne",
|
||
kind: "number",
|
||
default: 278.15,
|
||
required: true,
|
||
section: "Mesure (imposé)",
|
||
description: "Valeur cible en SI : K pour températures, Pa, W, kg/s…",
|
||
},
|
||
{
|
||
key: "gain",
|
||
label: "Gain",
|
||
kind: "number",
|
||
default: -0.5,
|
||
section: "Mesure (imposé)",
|
||
description: "Signe et échelle de l’erreur (consigne − mesure).",
|
||
},
|
||
{
|
||
key: "actuator_component",
|
||
label: "Composant actionné",
|
||
kind: "string",
|
||
default: "evap",
|
||
required: true,
|
||
section: "Actionneur (libre)",
|
||
description: "Composant dont on libère un facteur (souvent le même que mesuré).",
|
||
},
|
||
{
|
||
key: "actuator_factor",
|
||
label: "Facteur libre",
|
||
kind: "string",
|
||
default: "z_ua",
|
||
required: true,
|
||
section: "Actionneur (libre)",
|
||
description: "z_ua, opening, z_flow, z_power… Valeur initiale ci-dessous = point de départ.",
|
||
},
|
||
{
|
||
key: "initial",
|
||
label: "Valeur initiale",
|
||
kind: "number",
|
||
default: 1.0,
|
||
required: true,
|
||
section: "Actionneur (libre)",
|
||
description: "Départ du facteur libre (ex. Z_UA = 1).",
|
||
},
|
||
{
|
||
key: "min",
|
||
label: "Minimum",
|
||
kind: "number",
|
||
default: 0.2,
|
||
required: true,
|
||
section: "Actionneur (libre)",
|
||
},
|
||
{
|
||
key: "max",
|
||
label: "Maximum",
|
||
kind: "number",
|
||
default: 3.0,
|
||
required: true,
|
||
section: "Actionneur (libre)",
|
||
},
|
||
{ key: "band", label: "Bande de saturation", kind: "number", default: 5.0, section: "Réglages fins", min: 0.000001, advanced: true },
|
||
{ key: "smooth_eps", label: "Lissage saturation", kind: "number", default: 0.001, section: "Réglages fins", min: 0.000000001, advanced: true },
|
||
{ key: "alpha", label: "Lissage overrides", kind: "number", default: 0.001, section: "Réglages fins", min: 0.000000001, advanced: true },
|
||
],
|
||
},
|
||
|
||
// ── Compressors ────────────────────────────────────────────────────────
|
||
{
|
||
type: "IsentropicCompressor",
|
||
label: "Isentropic Compressor",
|
||
category: "Compressors",
|
||
description: "Compresseur physique : η_is + (option) ṁ = ρ·V·N·η_vol.",
|
||
help:
|
||
"Modèle : compression isentropique corrigée η_is.\n" +
|
||
"h_dis = h_suc + (h_is − h_suc) / η_is\n" +
|
||
"Mode émergent : ṁ = ρ_suc · V_d · N · η_vol · z_flow\n" +
|
||
"T_cond / T_evap = guesses d’init si pressions émergentes côté HX.\n" +
|
||
"Doc : docs/components/isentropic-compressor.md · Inventaire : correlations-and-maps.md",
|
||
docSlug: "isentropic-compressor",
|
||
ports: ["inlet", "outlet"],
|
||
color: "#6366f1",
|
||
params: [
|
||
{
|
||
key: "isentropic_efficiency",
|
||
label: "η isentropique",
|
||
kind: "number",
|
||
default: 0.75,
|
||
required: true,
|
||
section: "Model",
|
||
min: 0.05,
|
||
max: 1.0,
|
||
description: "η_is : h_dis = h_suc + (h_is−h_suc)/η_is",
|
||
sweepable: true,
|
||
sweepGroup: "machine",
|
||
},
|
||
{
|
||
key: "emergent_pressure",
|
||
label: "Pression émergente (ṁ par cylindrée)",
|
||
kind: "boolean",
|
||
default: true,
|
||
section: "Model",
|
||
description: "ON : ṁ = ρ·V·N·η_vol (recommandé machine réelle).",
|
||
},
|
||
{
|
||
key: "displacement_m3",
|
||
label: "Cylindrée V_d",
|
||
kind: "number",
|
||
unit: "m³/tr",
|
||
default: 5.0e-5,
|
||
section: "Displacement map",
|
||
min: 0,
|
||
description: "Volume balayé par tour — requis si pression émergente.",
|
||
},
|
||
{
|
||
key: "speed_hz",
|
||
label: "Vitesse N",
|
||
kind: "number",
|
||
unit: "tr/s",
|
||
default: 50.0,
|
||
section: "Displacement map",
|
||
min: 0,
|
||
},
|
||
{
|
||
key: "volumetric_efficiency",
|
||
label: "η volumétrique",
|
||
kind: "number",
|
||
default: 0.92,
|
||
section: "Displacement map",
|
||
min: 0.05,
|
||
max: 1.0,
|
||
},
|
||
{
|
||
key: "t_cond_k",
|
||
label: "T_cond guess",
|
||
kind: "number",
|
||
unit: "K",
|
||
default: 323.15,
|
||
section: "Init / design",
|
||
description: "Guess d’init (ou pin si non émergent).",
|
||
},
|
||
{
|
||
key: "t_evap_k",
|
||
label: "T_evap guess",
|
||
kind: "number",
|
||
unit: "K",
|
||
default: 275.15,
|
||
section: "Init / design",
|
||
},
|
||
{
|
||
key: "superheat_k",
|
||
label: "Superheat aspiration guess",
|
||
kind: "number",
|
||
unit: "K",
|
||
default: 5.0,
|
||
section: "Init / design",
|
||
},
|
||
],
|
||
},
|
||
{
|
||
type: "Compressor",
|
||
label: "Map Compressor (AHRI / SST-SDT)",
|
||
category: "Compressors",
|
||
description: "Deux modèles : AHRI 540 (M1–M10) ou polynôme bilinéaire SST/SDT.",
|
||
help:
|
||
"Choisis model_type :\n" +
|
||
"• Ahri540 : ṁ = M1·(1−(Ps/Pd)^(1/M2))·ρ·V·N/60 ; Ẇ = M3…M10\n" +
|
||
"• SstSdt : ṁ,Ẇ = a00 + a10·SST + a01·SDT + a11·SST·SDT (SST/SDT en K)\n" +
|
||
"Doc : compressor-ahri540.md · correlations-and-maps.md",
|
||
docSlug: "compressor-ahri540",
|
||
ports: ["inlet", "outlet"],
|
||
color: "#6366f1",
|
||
params: [
|
||
{
|
||
key: "model_type",
|
||
label: "Modèle de carte",
|
||
kind: "string",
|
||
default: "Ahri540",
|
||
section: "Model",
|
||
required: true,
|
||
options: [
|
||
{ value: "Ahri540", label: "AHRI 540 (M1–M10)" },
|
||
{ value: "SstSdt", label: "Polynôme SST / SDT (bilinéaire)" },
|
||
],
|
||
description: "Ahri540 = coefficients M1–M10. SstSdt = carte constructeur ṁ(SST,SDT), Ẇ(SST,SDT).",
|
||
},
|
||
{
|
||
key: "fluid",
|
||
label: "Frigorigène",
|
||
kind: "string",
|
||
default: "R134a",
|
||
section: "Machine",
|
||
required: true,
|
||
},
|
||
{
|
||
key: "speed_rpm",
|
||
label: "Vitesse",
|
||
kind: "number",
|
||
unit: "tr/min",
|
||
default: 3000,
|
||
required: true,
|
||
section: "Machine",
|
||
min: 1,
|
||
sweepable: true,
|
||
sweepGroup: "machine",
|
||
},
|
||
{
|
||
key: "displacement_m3",
|
||
label: "Cylindrée",
|
||
kind: "number",
|
||
unit: "m³",
|
||
default: 0.0005,
|
||
required: true,
|
||
section: "Machine",
|
||
min: 0,
|
||
},
|
||
{
|
||
key: "efficiency",
|
||
label: "Efficacité",
|
||
kind: "number",
|
||
default: 0.85,
|
||
section: "Machine",
|
||
min: 0.05,
|
||
max: 1,
|
||
},
|
||
// AHRI 540
|
||
{ key: "m1", label: "M1 (flow scale)", kind: "number", default: 0.85, section: "AHRI 540 (si Ahri540)", description: "ṁ ∝ M1·(1−(Ps/Pd)^(1/M2))" },
|
||
{ key: "m2", label: "M2 (PR exponent)", kind: "number", default: 2.5, section: "AHRI 540 (si Ahri540)", min: 0.01 },
|
||
{ key: "m3", label: "M3 (Ẇ cool const)", kind: "number", default: 500, section: "AHRI 540 (si Ahri540)", unit: "W" },
|
||
{ key: "m4", label: "M4 (Ẇ cool · PR)", kind: "number", default: 1500, section: "AHRI 540 (si Ahri540)" },
|
||
{ key: "m5", label: "M5 (Ẇ cool · Ts)", kind: "number", default: -2.5, section: "AHRI 540 (si Ahri540)" },
|
||
{ key: "m6", label: "M6 (Ẇ cool · Td)", kind: "number", default: 1.8, section: "AHRI 540 (si Ahri540)" },
|
||
{ key: "m7", label: "M7 (Ẇ heat const)", kind: "number", default: 600, section: "AHRI 540 (si Ahri540)", unit: "W", advanced: true },
|
||
{ key: "m8", label: "M8 (Ẇ heat · PR)", kind: "number", default: 1600, section: "AHRI 540 (si Ahri540)", advanced: true },
|
||
{ key: "m9", label: "M9 (Ẇ heat · Ts)", kind: "number", default: -3.0, section: "AHRI 540 (si Ahri540)", advanced: true },
|
||
{ key: "m10", label: "M10 (Ẇ heat · Td)", kind: "number", default: 2.0, section: "AHRI 540 (si Ahri540)", advanced: true },
|
||
// SST/SDT bilinear
|
||
{ key: "mf_a00", label: "ṁ a00", kind: "number", default: 0.05, section: "Map SST/SDT (si SstSdt)", description: "ṁ = a00 + a10·SST + a01·SDT + a11·SST·SDT (K)" },
|
||
{ key: "mf_a10", label: "ṁ a10 (×SST)", kind: "number", default: 0.001, section: "Map SST/SDT (si SstSdt)" },
|
||
{ key: "mf_a01", label: "ṁ a01 (×SDT)", kind: "number", default: 0.0005, section: "Map SST/SDT (si SstSdt)" },
|
||
{ key: "mf_a11", label: "ṁ a11 (×SST·SDT)", kind: "number", default: 0.00001, section: "Map SST/SDT (si SstSdt)" },
|
||
{ key: "pw_b00", label: "Ẇ b00", kind: "number", default: 1000, unit: "W", section: "Map SST/SDT (si SstSdt)", description: "Ẇ = b00 + b10·SST + b01·SDT + b11·SST·SDT (K)" },
|
||
{ key: "pw_b10", label: "Ẇ b10 (×SST)", kind: "number", default: 50, section: "Map SST/SDT (si SstSdt)" },
|
||
{ key: "pw_b01", label: "Ẇ b01 (×SDT)", kind: "number", default: 30, section: "Map SST/SDT (si SstSdt)" },
|
||
{ key: "pw_b11", label: "Ẇ b11 (×SST·SDT)", kind: "number", default: 0.5, section: "Map SST/SDT (si SstSdt)" },
|
||
],
|
||
},
|
||
{
|
||
type: "CentrifugalCompressor",
|
||
label: "Centrifugal Compressor",
|
||
category: "Compressors",
|
||
description: "Centrifugal compressor with φ–Mach polytropic map (CLI-wired).",
|
||
help:
|
||
"Carte φ / Mach → tête polytropique et η_p. VFD via speed_rpm.\n" +
|
||
"Modèle encore simplifié côté solveur (Jacobien partiel).",
|
||
ports: ["inlet", "outlet"],
|
||
color: "#4338ca",
|
||
params: [
|
||
{ key: "diameter_m", label: "Impeller diameter", kind: "number", unit: "m", default: 0.25, required: true },
|
||
{ key: "speed_rpm", label: "Speed", kind: "number", unit: "rpm", default: 9000.0, required: true, sweepable: true, sweepGroup: "machine" },
|
||
{ key: "gas_constant", label: "Gas constant R", kind: "number", unit: "J/kg·K", default: 188.9, advanced: true },
|
||
{ key: "gamma", label: "Heat capacity ratio γ", kind: "number", default: 1.12, advanced: true },
|
||
],
|
||
},
|
||
{
|
||
type: "ScrewEconomizerCompressor",
|
||
label: "Screw Compressor (Economizer)",
|
||
category: "Compressors",
|
||
description: "Vis 3 ports — polynôme bilinéaire SST/SDT + presets.",
|
||
help:
|
||
"Carte bilinéaire :\n" +
|
||
"ṁ = a00 + a10·SST + a01·SDT + a11·SST·SDT\n" +
|
||
"Ẇ = b00 + b10·SST + b01·SDT + b11·SST·SDT\n" +
|
||
"Presets : bitzer_generic_200kw, grasso_generic_200kw.\n" +
|
||
"Ports : suction, discharge, economizer.\n" +
|
||
"Doc : screw-economizer-compressor.md · correlations-and-maps.md",
|
||
docSlug: "screw-economizer-compressor",
|
||
ports: ["suction", "discharge", "economizer"],
|
||
color: "#4f46e5",
|
||
params: [
|
||
{
|
||
key: "preset",
|
||
label: "Preset carte",
|
||
kind: "string",
|
||
default: "bitzer_generic_200kw",
|
||
section: "Model",
|
||
options: [
|
||
{ value: "bitzer_generic_200kw", label: "Bitzer generic ~200 kW" },
|
||
{ value: "grasso_generic_200kw", label: "Grasso generic ~200 kW" },
|
||
{ value: "", label: "Custom (defaults)" },
|
||
],
|
||
description: "Remplit les coeffs mf_* / pw_* (surchargeables).",
|
||
},
|
||
{
|
||
key: "frequency_hz",
|
||
label: "Fréquence",
|
||
kind: "number",
|
||
unit: "Hz",
|
||
default: 50.0,
|
||
section: "Machine",
|
||
sweepable: true,
|
||
sweepGroup: "machine",
|
||
},
|
||
{
|
||
key: "nominal_frequency_hz",
|
||
label: "Fréquence nominale",
|
||
kind: "number",
|
||
unit: "Hz",
|
||
default: 50.0,
|
||
section: "Machine",
|
||
},
|
||
{
|
||
key: "mechanical_efficiency",
|
||
label: "η mécanique",
|
||
kind: "number",
|
||
default: 0.92,
|
||
section: "Machine",
|
||
min: 0.05,
|
||
max: 1,
|
||
},
|
||
{
|
||
key: "economizer_fraction",
|
||
label: "Fraction éco ṁ",
|
||
kind: "number",
|
||
default: 0.13,
|
||
section: "Machine",
|
||
min: 0,
|
||
max: 1,
|
||
},
|
||
{
|
||
key: "volume_index",
|
||
label: "Volume index Vi",
|
||
kind: "number",
|
||
default: 2.8,
|
||
section: "Machine",
|
||
min: 1.1,
|
||
max: 6,
|
||
description: "Built-in Vi; slide valve reduces effective Vi.",
|
||
sweepable: true,
|
||
sweepGroup: "machine",
|
||
},
|
||
{
|
||
key: "slide_valve_position",
|
||
label: "Slide valve (0–1)",
|
||
kind: "number",
|
||
default: 1.0,
|
||
section: "Machine",
|
||
min: 0.05,
|
||
max: 1,
|
||
sweepable: true,
|
||
sweepGroup: "machine",
|
||
},
|
||
// Mass-flow bilinear (Bitzer defaults as numbers)
|
||
{ key: "mf_a00", label: "ṁ a00", kind: "number", default: 1.35, section: "Map ṁ (SST,SDT)", description: "ṁ = a00 + a10·SST + a01·SDT + a11·SST·SDT" },
|
||
{ key: "mf_a10", label: "ṁ a10 (×SST)", kind: "number", default: 0.004, section: "Map ṁ (SST,SDT)" },
|
||
{ key: "mf_a01", label: "ṁ a01 (×SDT)", kind: "number", default: -0.0025, section: "Map ṁ (SST,SDT)" },
|
||
{ key: "mf_a11", label: "ṁ a11 (×SST·SDT)", kind: "number", default: 0.000012, section: "Map ṁ (SST,SDT)" },
|
||
{ key: "pw_b00", label: "Ẇ b00", kind: "number", default: 58000, unit: "W", section: "Map Ẇ (SST,SDT)", description: "Ẇ = b00 + b10·SST + b01·SDT + b11·SST·SDT" },
|
||
{ key: "pw_b10", label: "Ẇ b10 (×SST)", kind: "number", default: 180, section: "Map Ẇ (SST,SDT)" },
|
||
{ key: "pw_b01", label: "Ẇ b01 (×SDT)", kind: "number", default: -280, section: "Map Ẇ (SST,SDT)" },
|
||
{ key: "pw_b11", label: "Ẇ b11 (×SST·SDT)", kind: "number", default: 0.4, section: "Map Ẇ (SST,SDT)" },
|
||
],
|
||
},
|
||
|
||
// ── Heat exchangers ────────────────────────────────────────────────────
|
||
{
|
||
type: "Condenser",
|
||
label: "Condenser",
|
||
category: "Heat Exchangers",
|
||
description: "Condenseur frigo avec secondaire eau/air (ε-NTU).",
|
||
help:
|
||
"Rôle : rejette la chaleur du frigorigène vers l’eau ou l’air.\n\n" +
|
||
"Ports : inlet/outlet frigo · secondary_in/out caloporteur.\n\n" +
|
||
"ΔP frigo : dp_model=msh (Müller–Steinhagen–Heck + accélération) avec géométrie tube, " +
|
||
"ou quadratic (dp_nominal), ou isobaric.\n\n" +
|
||
"Machine réelle : cocher « Solve condensing pressure » et câbler Source/Sink secondaires.\n" +
|
||
"Calibration : Fixed sur SDT + Z_UA libre (Z_UA défaut = 1).",
|
||
docSlug: "condenser",
|
||
ports: ["inlet", "outlet", "secondary_inlet", "secondary_outlet"],
|
||
color: "#ef4444",
|
||
params: [
|
||
{ key: "manufacturer", label: "Manufacturer", kind: "string", default: "", section: "Identification" },
|
||
{ key: "model", label: "Model / reference", kind: "string", default: "", section: "Identification" },
|
||
{ key: "fluid", label: "Refrigerant", kind: "string", default: "R134a", section: "Fluids" },
|
||
{ key: "secondary_fluid", label: "Secondary fluid", kind: "string", default: "Water", section: "Fluids" },
|
||
{ key: "ua", label: "UA", kind: "number", unit: "W/K", default: 5000.0, required: true, section: "Thermal model", min: 0.0, sweepable: true, sweepGroup: "thermal" },
|
||
{ key: "t_sat_k", label: "Fixed saturation temperature", kind: "number", unit: "K", default: 323.15, section: "Thermal model", description: "Used only in fixed-pressure mode. Do not treat it as a solved-cycle input when emergent pressure is enabled." },
|
||
{
|
||
key: "secondary_inlet_temp_c",
|
||
label: "Secondary inlet T (rating only)",
|
||
kind: "number",
|
||
unit: "°C",
|
||
default: 30.0,
|
||
section: "Secondary side (rating)",
|
||
description: "Rating scalar. Prefer live secondary ports + BrineSource for system mode.",
|
||
},
|
||
{
|
||
key: "secondary_mass_flow_kg_s",
|
||
label: "Secondary mass flow (rating only)",
|
||
kind: "number",
|
||
unit: "kg/s",
|
||
default: 2.0,
|
||
section: "Secondary side (rating)",
|
||
min: 0.0,
|
||
},
|
||
{
|
||
key: "secondary_cp_j_per_kgk",
|
||
label: "Secondary specific heat (rating only)",
|
||
kind: "number",
|
||
unit: "J/kg·K",
|
||
default: 4186.0,
|
||
section: "Secondary side (rating)",
|
||
min: 0.0,
|
||
advanced: true,
|
||
},
|
||
{ key: "secondary_humidity_ratio", label: "Secondary humidity ratio", kind: "number", unit: "kg/kg", default: 0.0, section: "Secondary side (rating)", min: 0.0, advanced: true },
|
||
{
|
||
key: "dp_model",
|
||
label: "Refrigerant ΔP model",
|
||
kind: "string",
|
||
default: "msh",
|
||
section: "Hydraulics",
|
||
options: [
|
||
{ value: "msh", label: "MSH 1986 (tube, + accel)" },
|
||
{ value: "friedel", label: "Friedel 1979 (tube, + accel)" },
|
||
{ value: "quadratic", label: "Quadratic (dp_nominal)" },
|
||
{ value: "isobaric", label: "Isobaric (ΔP = 0)" },
|
||
],
|
||
description:
|
||
"MSH = NIST EVAP-COND default two-phase friction at mean quality + acceleration. Quadratic = Modelica Buildings k·ṁ². Flooded shell-side → isobaric.",
|
||
},
|
||
{ key: "tube_length_m", label: "Tube length", kind: "number", unit: "m", default: 6.0, section: "Hydraulics", min: 0.0, description: "Path length for MSH/Friedel." },
|
||
{ key: "tube_diameter_m", label: "Tube diameter", kind: "number", unit: "m", default: 0.0095, section: "Hydraulics", min: 0.0, advanced: true },
|
||
{ key: "n_parallel_tubes", label: "Parallel tubes", kind: "number", default: 2, section: "Hydraulics", min: 1, advanced: true },
|
||
{
|
||
key: "rated_pressure_drop_pa",
|
||
label: "Design ΔP (quadratic)",
|
||
kind: "number",
|
||
unit: "Pa",
|
||
default: 15000,
|
||
section: "Hydraulics",
|
||
min: 0.0,
|
||
advanced: true,
|
||
description: "Only when dp_model=quadratic. Calibrates k = ΔP/ṁ².",
|
||
},
|
||
{
|
||
key: "rated_mass_flow_kg_s",
|
||
label: "Design ṁ (quadratic)",
|
||
kind: "number",
|
||
unit: "kg/s",
|
||
default: 0.05,
|
||
section: "Hydraulics",
|
||
min: 0.0,
|
||
advanced: true,
|
||
},
|
||
{
|
||
key: "pressure_drop_coeff_pa_s2_kg2",
|
||
label: "Pressure-drop coefficient k",
|
||
kind: "number",
|
||
unit: "Pa·s²/kg²",
|
||
section: "Hydraulics",
|
||
min: 0.0,
|
||
advanced: true,
|
||
description: "Direct k for quadratic mode.",
|
||
},
|
||
{
|
||
key: "secondary_rated_pressure_drop_pa",
|
||
label: "Water/air design ΔP",
|
||
kind: "number",
|
||
unit: "Pa",
|
||
default: 30000,
|
||
section: "Secondary hydraulics",
|
||
min: 0.0,
|
||
description:
|
||
"Secondary-side ΔP at rated ṁ (Modelica dp_nominal). NOT the refrigerant tube MSH model. 0 = isobaric water path.",
|
||
},
|
||
{
|
||
key: "secondary_rated_m_flow_kg_s",
|
||
label: "Water/air design ṁ",
|
||
kind: "number",
|
||
unit: "kg/s",
|
||
default: 0.45,
|
||
section: "Secondary hydraulics",
|
||
min: 0.0,
|
||
description: "Pairs with Water/air design ΔP → k = ΔP/ṁ².",
|
||
},
|
||
{ key: "emergent_pressure", label: "Solve condensing pressure", kind: "boolean", default: true, section: "Solved-cycle mode", description: "ON (recommandé machine): P_cond émerge du bilan — pas un Dirichlet fixe (esprit Modelica cycle fermé)." },
|
||
{ key: "subcooling_k", label: "Outlet subcooling closure", kind: "number", unit: "K", default: 5.0, section: "Solved-cycle mode", min: 0.0, description: "FIX residual when emergent_pressure is ON (+1 eq, closes P_cond with energy balance)." },
|
||
{ key: "fan_head_pressure_target_c", label: "Fan head-pressure target", kind: "number", unit: "°C", section: "Controls", advanced: true },
|
||
{ key: "flooded_head_pressure_target_c", label: "Flooded head-pressure target", kind: "number", unit: "°C", section: "Controls", advanced: true },
|
||
{ key: "skip_pressure_eq", label: "Skip pressure equation", kind: "boolean", default: false, section: "Solver structure", advanced: true },
|
||
{
|
||
key: "z_ua",
|
||
label: "Z_UA (UA factor)",
|
||
kind: "number",
|
||
default: 1.0,
|
||
section: "Calibration",
|
||
min: 0.000001,
|
||
fixable: true,
|
||
defaultFixed: true,
|
||
actuatorFactor: "z_ua",
|
||
freeMin: 0.2,
|
||
freeMax: 3.0,
|
||
description: "Fixed = valeur figée. Décocher Fixed = libre (calibration).",
|
||
},
|
||
{
|
||
key: "z_dp",
|
||
label: "Z_dP (pressure-drop factor)",
|
||
kind: "number",
|
||
default: 1.0,
|
||
section: "Calibration",
|
||
min: 0.000001,
|
||
advanced: true,
|
||
fixable: true,
|
||
defaultFixed: true,
|
||
actuatorFactor: "z_dp",
|
||
freeMin: 0.2,
|
||
freeMax: 3.0,
|
||
},
|
||
],
|
||
},
|
||
{
|
||
type: "Evaporator",
|
||
label: "Evaporator",
|
||
category: "Heat Exchangers",
|
||
description: "Évaporateur DX (détente directe) avec secondaire eau/brine.",
|
||
help:
|
||
"Rôle : évaporateur à détente directe (sortie surchauffée).\n\n" +
|
||
"Ports : inlet/outlet frigo · secondary_in/out.\n\n" +
|
||
"Différence flooded : ici la sortie n’est pas noyée — superheat en sortie.\n" +
|
||
"Calibration : Fixed sur SST + Z_UA libre (défaut Z_UA = 1).",
|
||
docSlug: "evaporator",
|
||
ports: ["inlet", "outlet", "secondary_inlet", "secondary_outlet"],
|
||
color: "#3b82f6",
|
||
params: [
|
||
{ key: "manufacturer", label: "Manufacturer", kind: "string", default: "", section: "Identification" },
|
||
{ key: "model", label: "Model / reference", kind: "string", default: "", section: "Identification" },
|
||
{ key: "fluid", label: "Refrigerant", kind: "string", default: "R134a", section: "Fluids" },
|
||
{ key: "secondary_fluid", label: "Secondary fluid", kind: "string", default: "Water", section: "Fluids" },
|
||
{ key: "ua", label: "UA", kind: "number", unit: "W/K", default: 6000.0, required: true, section: "Thermal model", min: 0.0, sweepable: true, sweepGroup: "thermal" },
|
||
{ key: "t_sat_k", label: "Fixed saturation temperature", kind: "number", unit: "K", default: 275.15, section: "Thermal model", description: "Used only in fixed-pressure mode." },
|
||
{ key: "superheat_k", label: "Outlet superheat closure", kind: "number", unit: "K", default: 5.0, section: "Thermal model", min: 0.0 },
|
||
{
|
||
key: "z_ua",
|
||
label: "Z_UA (UA factor)",
|
||
kind: "number",
|
||
default: 1.0,
|
||
section: "Calibration",
|
||
min: 0.000001,
|
||
fixable: true,
|
||
defaultFixed: true,
|
||
actuatorFactor: "z_ua",
|
||
freeMin: 0.2,
|
||
freeMax: 3.0,
|
||
description: "Fixed = figé. Décocher Fixed = libre pour le solveur.",
|
||
},
|
||
{
|
||
key: "z_dp",
|
||
label: "Z_dP (pressure-drop factor)",
|
||
kind: "number",
|
||
default: 1.0,
|
||
section: "Calibration",
|
||
min: 0.000001,
|
||
advanced: true,
|
||
fixable: true,
|
||
defaultFixed: true,
|
||
actuatorFactor: "z_dp",
|
||
freeMin: 0.2,
|
||
freeMax: 3.0,
|
||
},
|
||
{
|
||
key: "secondary_inlet_temp_c",
|
||
label: "Secondary inlet T (rating only)",
|
||
kind: "number",
|
||
unit: "°C",
|
||
default: 12.0,
|
||
section: "Secondary side (rating)",
|
||
description: "Rating scalar. Prefer live secondary ports + BrineSource for system mode.",
|
||
},
|
||
{
|
||
key: "secondary_mass_flow_kg_s",
|
||
label: "Secondary mass flow (rating only)",
|
||
kind: "number",
|
||
unit: "kg/s",
|
||
default: 1.5,
|
||
section: "Secondary side (rating)",
|
||
min: 0.0,
|
||
},
|
||
{
|
||
key: "secondary_cp_j_per_kgk",
|
||
label: "Secondary specific heat (rating only)",
|
||
kind: "number",
|
||
unit: "J/kg·K",
|
||
default: 4186.0,
|
||
section: "Secondary side (rating)",
|
||
min: 0.0,
|
||
advanced: true,
|
||
},
|
||
{ key: "secondary_humidity_ratio", label: "Secondary humidity ratio", kind: "number", unit: "kg/kg", default: 0.0, section: "Secondary side (rating)", min: 0.0, advanced: true },
|
||
{
|
||
key: "dp_model",
|
||
label: "Refrigerant ΔP model",
|
||
kind: "string",
|
||
default: "msh",
|
||
section: "Hydraulics",
|
||
options: [
|
||
{ value: "msh", label: "MSH 1986 (tube, + accel)" },
|
||
{ value: "friedel", label: "Friedel 1979 (tube, + accel)" },
|
||
{ value: "quadratic", label: "Quadratic (dp_nominal)" },
|
||
{ value: "isobaric", label: "Isobaric (ΔP = 0)" },
|
||
],
|
||
description: "DX tube ΔP. For flooded shell-side use FloodedEvaporator (ΔP ≈ 0).",
|
||
},
|
||
{ key: "tube_length_m", label: "Tube length", kind: "number", unit: "m", default: 6.0, section: "Hydraulics", min: 0.0 },
|
||
{ key: "tube_diameter_m", label: "Tube diameter", kind: "number", unit: "m", default: 0.0095, section: "Hydraulics", min: 0.0, advanced: true },
|
||
{ key: "n_parallel_tubes", label: "Parallel tubes", kind: "number", default: 2, section: "Hydraulics", min: 1, advanced: true },
|
||
{
|
||
key: "rated_pressure_drop_pa",
|
||
label: "Design ΔP (quadratic)",
|
||
kind: "number",
|
||
unit: "Pa",
|
||
default: 15000,
|
||
section: "Hydraulics",
|
||
min: 0.0,
|
||
advanced: true,
|
||
},
|
||
{
|
||
key: "rated_mass_flow_kg_s",
|
||
label: "Design ṁ (quadratic)",
|
||
kind: "number",
|
||
unit: "kg/s",
|
||
default: 0.05,
|
||
section: "Hydraulics",
|
||
min: 0.0,
|
||
advanced: true,
|
||
},
|
||
{
|
||
key: "pressure_drop_coeff_pa_s2_kg2",
|
||
label: "Pressure-drop coefficient k",
|
||
kind: "number",
|
||
unit: "Pa·s²/kg²",
|
||
section: "Hydraulics",
|
||
min: 0.0,
|
||
advanced: true,
|
||
},
|
||
{
|
||
key: "secondary_rated_pressure_drop_pa",
|
||
label: "Water/air design ΔP",
|
||
kind: "number",
|
||
unit: "Pa",
|
||
default: 30000,
|
||
section: "Secondary hydraulics",
|
||
min: 0.0,
|
||
description: "Secondary-side ΔP at rated ṁ. Distinct from refrigerant dp_model. 0 = isobaric.",
|
||
},
|
||
{
|
||
key: "secondary_rated_m_flow_kg_s",
|
||
label: "Water/air design ṁ",
|
||
kind: "number",
|
||
unit: "kg/s",
|
||
default: 0.5,
|
||
section: "Secondary hydraulics",
|
||
min: 0.0,
|
||
},
|
||
{ key: "emergent_pressure", label: "Solve evaporating pressure", kind: "boolean", default: true, section: "Solved-cycle mode", description: "ON (recommandé machine): P_evap émerge du bilan — pas un Dirichlet fixe." },
|
||
{
|
||
key: "superheat_regulated",
|
||
label: "Regulate superheat with EXV controller",
|
||
kind: "boolean",
|
||
default: false,
|
||
section: "Solved-cycle mode",
|
||
description: "Drops SH residual (−1 eq). Pair with SaturatedController → EXV opening (FREE).",
|
||
},
|
||
{ key: "skip_pressure_eq", label: "Skip pressure equation", kind: "boolean", default: false, section: "Solver structure", advanced: true },
|
||
],
|
||
},
|
||
{
|
||
type: "MchxCondenserCoil",
|
||
label: "MCHX Condenser Coil",
|
||
category: "Heat Exchangers",
|
||
description: "Multi-channel heat exchanger air-cooled condenser coil.",
|
||
ports: ["inlet", "outlet", "secondary_inlet", "secondary_outlet"],
|
||
color: "#f97316",
|
||
params: [
|
||
{ key: "manufacturer", label: "Manufacturer", kind: "string", default: "", section: "Identification", description: "Supplier or coil manufacturer. Stored as project traceability data." },
|
||
{ key: "model", label: "Model / reference", kind: "string", default: "", section: "Identification", description: "Manufacturer model, selection reference, or internal equipment code." },
|
||
{ key: "ua_nominal_kw_k", label: "Nominal UA", kind: "number", unit: "kW/K", default: 15.0, required: true, section: "Thermal model", min: 0.001, description: "Overall conductance at nominal air flow." },
|
||
{ key: "n_air_exponent", label: "Air-flow exponent", kind: "number", default: 0.5, section: "Thermal model", min: 0.0, max: 2.0, description: "Exponent used to scale UA with air-flow ratio." },
|
||
{ key: "coil_index", label: "Coil index", kind: "number", default: 0, section: "Identification", min: 0, step: 1 },
|
||
{ key: "air_inlet_temp_c", label: "Air inlet temperature", kind: "number", unit: "°C", default: 35.0, section: "Air side" },
|
||
{ key: "fan_speed", label: "Fan speed ratio", kind: "number", default: 1.0, section: "Air side", min: 0.0, max: 1.0, step: 0.01, sweepable: true, sweepGroup: "machine" },
|
||
],
|
||
},
|
||
{
|
||
type: "AirCooledCondenser",
|
||
label: "Air-Cooled Condenser",
|
||
category: "Heat Exchangers",
|
||
description: "Condenser with air-side fan model. The caloporteur ports represent the ambient air stream.",
|
||
ports: ["inlet", "outlet", "secondary_inlet", "secondary_outlet"],
|
||
color: "#f59e0b",
|
||
params: [
|
||
{ key: "manufacturer", label: "Manufacturer", kind: "string", default: "", section: "Identification" },
|
||
{ key: "model", label: "Model / reference", kind: "string", default: "", section: "Identification" },
|
||
{ key: "fluid", label: "Refrigerant", kind: "string", default: "R134a", section: "Fluids" },
|
||
{ key: "ua", label: "UA at full fan", kind: "number", unit: "W/K", default: 4000.0, required: true, section: "Thermal model", min: 0.0, sweepable: true, sweepGroup: "thermal" },
|
||
{ key: "oat_k", label: "Outdoor air temperature", kind: "number", unit: "K", default: 308.15, section: "Air side", description: "Ambient dry-bulb temperature used by the condenser model.", sweepable: true, sweepGroup: "boundaries" },
|
||
{ key: "approach_k", label: "Condensing approach", kind: "number", unit: "K", default: 12.0, section: "Thermal model", min: 0.0 },
|
||
],
|
||
},
|
||
{
|
||
type: "FinCoilCondenser",
|
||
label: "Finned-Tube Condenser Coil",
|
||
category: "Heat Exchangers",
|
||
description:
|
||
"Round-tube plate-fin air-cooled condenser. UA and condensing temperature are derived from the actual coil face, tube rows, fin pitch and air velocity.",
|
||
ports: ["inlet", "outlet", "secondary_inlet", "secondary_outlet"],
|
||
color: "#d97706",
|
||
params: [
|
||
{ key: "manufacturer", label: "Manufacturer", kind: "string", default: "", section: "Identification", description: "Coil supplier or OEM." },
|
||
{ key: "model", label: "Model / reference", kind: "string", default: "", section: "Identification", description: "Supplier selection reference or equipment code." },
|
||
{ key: "fluid", label: "Refrigerant", kind: "string", default: "R134a", section: "Fluids" },
|
||
{ key: "face_width_m", label: "Coil face width", kind: "number", unit: "m", default: 1.5, required: true, section: "Coil geometry", min: 0.01 },
|
||
{ key: "face_height_m", label: "Coil face height", kind: "number", unit: "m", default: 1.0, required: true, section: "Coil geometry", min: 0.01 },
|
||
{ key: "n_rows", label: "Tube rows", kind: "number", default: 3, required: true, section: "Coil geometry", min: 1, step: 1 },
|
||
{
|
||
key: "fin_type",
|
||
label: "Fin type",
|
||
kind: "string",
|
||
default: "louvered",
|
||
section: "Fin geometry",
|
||
options: [
|
||
{ value: "louvered", label: "Louvered — Chang & Wang" },
|
||
{ value: "slit", label: "Slit fin" },
|
||
{ value: "wavy", label: "Wavy / corrugated" },
|
||
{ value: "plain", label: "Plain fin" },
|
||
],
|
||
},
|
||
{ key: "fin_pitch_fpi", label: "Fin pitch", kind: "number", unit: "FPI", default: 14.0, required: true, section: "Fin geometry", min: 1.0, description: "Number of fins per inch." },
|
||
{ key: "fin_thickness_mm", label: "Fin thickness", kind: "number", unit: "mm", default: 0.1, section: "Fin geometry", min: 0.01 },
|
||
{ key: "louver_pitch_mm", label: "Louver pitch", kind: "number", unit: "mm", default: 1.4, section: "Fin geometry", min: 0.01 },
|
||
{ key: "tube_od_mm", label: "Tube outside diameter", kind: "number", unit: "mm", default: 9.525, required: true, section: "Tube geometry", min: 0.1 },
|
||
{ key: "tube_pitch_mm", label: "Transverse tube pitch", kind: "number", unit: "mm", default: 25.4, required: true, section: "Tube geometry", min: 0.1, description: "Longitudinal pitch is derived using the staggered-tube ratio." },
|
||
{ key: "oat_k", label: "Outdoor air temperature", kind: "number", unit: "K", default: 308.15, required: true, section: "Air side", sweepable: true, sweepGroup: "boundaries" },
|
||
{ key: "air_face_velocity_m_s", label: "Air face velocity", kind: "number", unit: "m/s", default: 2.5, required: true, section: "Air side", min: 0.01, sweepable: true, sweepGroup: "boundaries" },
|
||
{ key: "design_capacity_kw", label: "Design heat rejection", kind: "number", unit: "kW", default: 100.0, required: true, section: "Design point", min: 0.01 },
|
||
{
|
||
key: "wet_surface",
|
||
label: "Wet air-side (Wang)",
|
||
kind: "boolean",
|
||
default: false,
|
||
section: "Air side",
|
||
description: "Apply Wang wet j-factor correction when condensate forms.",
|
||
},
|
||
],
|
||
},
|
||
{
|
||
type: "BphxEvaporator",
|
||
label: "Brazed Plate Evaporator",
|
||
category: "Heat Exchangers",
|
||
description: "Évaporateur à plaques brasées : géométrie + corrélation Longo/Shah → UA.",
|
||
help:
|
||
"Modèle : corrélation biphasique (Longo 2004 / Shah 1979 / Shah 2021) estime h et UA à partir des plaques, puis le solveur utilise un HX ε-NTU.\n\n" +
|
||
"DX uniquement (sortie surchauffée). Pour un noyé calandre/tubes → FloodedEvaporator.\n\n" +
|
||
"Corrélations et formules : docs/components/bphx.md",
|
||
docSlug: "bphx",
|
||
ports: ["inlet", "outlet", "secondary_inlet", "secondary_outlet"],
|
||
color: "#0891b2",
|
||
params: [
|
||
{ key: "manufacturer", label: "Manufacturer", kind: "string", default: "", section: "Identification" },
|
||
{ key: "model", label: "Model / reference", kind: "string", default: "", section: "Identification" },
|
||
{ key: "refrigerant", label: "Refrigerant", kind: "string", default: "R134a", section: "Fluids" },
|
||
{ key: "secondary_fluid", label: "Secondary fluid", kind: "string", default: "Water", section: "Fluids", description: "Water, brine, or glycol solution connected to the secondary ports." },
|
||
{ key: "n_plates", label: "Number of plates", kind: "number", default: 20, required: true, section: "Plate pack", min: 2, step: 1 },
|
||
{ key: "plate_length_m", label: "Effective plate length", kind: "number", unit: "m", default: 0.25, section: "Plate pack", min: 0.001 },
|
||
{ key: "plate_width_m", label: "Effective plate width", kind: "number", unit: "m", default: 0.05, section: "Plate pack", min: 0.001 },
|
||
{ key: "plate_thickness_mm", label: "Plate thickness", kind: "number", unit: "mm", default: 0.6, section: "Plate pack", min: 0.01 },
|
||
{ key: "channel_spacing_mm", label: "Channel spacing", kind: "number", unit: "mm", default: 1.5, section: "Corrugation", min: 0.01 },
|
||
{ key: "chevron_angle_deg", label: "Chevron angle", kind: "number", unit: "°", default: 60.0, section: "Corrugation", min: 10.0, max: 80.0 },
|
||
{ key: "corrugation_pitch_mm", label: "Corrugation pitch", kind: "number", unit: "mm", default: 3.0, section: "Corrugation", min: 0.01 },
|
||
{ key: "dh_m", label: "Hydraulic diameter override", kind: "number", unit: "m", section: "Direct manufacturer data", min: 0.000001, advanced: true, description: "Optional direct override. Use together with heat-transfer area when the supplier provides both values." },
|
||
{ key: "area_m2", label: "Heat-transfer area override", kind: "number", unit: "m²", section: "Direct manufacturer data", min: 0.000001, advanced: true },
|
||
{ key: "target_superheat_k", label: "Target superheat", kind: "number", unit: "K", default: 5.0, section: "Operating model", min: 0.0, description: "Brazed plate evaporators are Direct Expansion (DX) only in this project — the refrigerant outlet is always superheated. A flooded design is a system-level property (Drum + recirculation loop); use the Flooded Evaporator (shell-and-tube) component for that." },
|
||
{
|
||
key: "emergent_pressure",
|
||
label: "Solve evaporating pressure",
|
||
kind: "boolean",
|
||
default: true,
|
||
section: "Solved-cycle mode",
|
||
description:
|
||
"ON: +1 outlet-closure residual pins h_out to target superheat so P_evap emerges from the secondary balance.",
|
||
},
|
||
{
|
||
key: "correlation",
|
||
label: "Two-phase correlation",
|
||
kind: "string",
|
||
default: "Longo2004",
|
||
section: "Heat-transfer model",
|
||
options: [
|
||
{ value: "Longo2004", label: "Longo 2004" },
|
||
{ value: "Shah1979", label: "Shah 1979" },
|
||
{ value: "Shah2021", label: "Shah 2021" },
|
||
],
|
||
},
|
||
{
|
||
key: "dp_correlation",
|
||
label: "Pressure-drop correlation",
|
||
kind: "string",
|
||
default: "SimplifiedChannel",
|
||
section: "Pressure drop",
|
||
description:
|
||
"Channel friction on both hot and cold sides (independent of HTC). Default SimplifiedChannel; Martin1996 uses chevron angle.",
|
||
options: [
|
||
{ value: "SimplifiedChannel", label: "Simplified channel (default)" },
|
||
{ value: "Martin1996", label: "Martin 1996 (chevron)" },
|
||
],
|
||
},
|
||
{ key: "ua", label: "UA override", kind: "number", unit: "W/K", section: "Calibration", min: 0.0, advanced: true },
|
||
{
|
||
key: "z_ua",
|
||
label: "Z_UA (UA factor)",
|
||
kind: "number",
|
||
default: 1.0,
|
||
section: "Calibration",
|
||
min: 0.000001,
|
||
fixable: true,
|
||
defaultFixed: true,
|
||
actuatorFactor: "z_ua",
|
||
freeMin: 0.2,
|
||
freeMax: 3.0,
|
||
},
|
||
{
|
||
key: "z_dp",
|
||
label: "Z_dP (pressure-drop factor)",
|
||
kind: "number",
|
||
default: 1.0,
|
||
section: "Calibration",
|
||
min: 0.000001,
|
||
fixable: true,
|
||
defaultFixed: true,
|
||
actuatorFactor: "z_dp",
|
||
freeMin: 0.2,
|
||
freeMax: 3.0,
|
||
},
|
||
],
|
||
},
|
||
{
|
||
type: "BphxCondenser",
|
||
label: "Brazed Plate Condenser",
|
||
category: "Heat Exchangers",
|
||
description: "Condenseur à plaques brasées : géométrie + corrélation Longo/Shah → UA.",
|
||
help:
|
||
"Même famille que BphxEvaporator. Corrélation de condensation (Longo/Shah) → h → UA, solveur ε-NTU.\n\n" +
|
||
"Détail des Nu / Re_eq / ΔP : docs/components/bphx.md",
|
||
docSlug: "bphx",
|
||
ports: ["inlet", "outlet", "secondary_inlet", "secondary_outlet"],
|
||
color: "#dc2626",
|
||
params: [
|
||
{ key: "manufacturer", label: "Manufacturer", kind: "string", default: "", section: "Identification" },
|
||
{ key: "model", label: "Model / reference", kind: "string", default: "", section: "Identification" },
|
||
{ key: "refrigerant", label: "Refrigerant", kind: "string", default: "R134a", section: "Fluids" },
|
||
{ key: "secondary_fluid", label: "Secondary fluid", kind: "string", default: "Water", section: "Fluids" },
|
||
{ key: "n_plates", label: "Number of plates", kind: "number", default: 20, required: true, section: "Plate pack", min: 2, step: 1 },
|
||
{ key: "plate_length_m", label: "Effective plate length", kind: "number", unit: "m", default: 0.25, section: "Plate pack", min: 0.001 },
|
||
{ key: "plate_width_m", label: "Effective plate width", kind: "number", unit: "m", default: 0.05, section: "Plate pack", min: 0.001 },
|
||
{ key: "plate_thickness_mm", label: "Plate thickness", kind: "number", unit: "mm", default: 0.6, section: "Plate pack", min: 0.01 },
|
||
{ key: "channel_spacing_mm", label: "Channel spacing", kind: "number", unit: "mm", default: 1.5, section: "Corrugation", min: 0.01 },
|
||
{ key: "chevron_angle_deg", label: "Chevron angle", kind: "number", unit: "°", default: 60.0, section: "Corrugation", min: 10.0, max: 80.0 },
|
||
{ key: "corrugation_pitch_mm", label: "Corrugation pitch", kind: "number", unit: "mm", default: 3.0, section: "Corrugation", min: 0.01 },
|
||
{ key: "dh_m", label: "Hydraulic diameter override", kind: "number", unit: "m", section: "Direct manufacturer data", min: 0.000001, advanced: true },
|
||
{ key: "area_m2", label: "Heat-transfer area override", kind: "number", unit: "m²", section: "Direct manufacturer data", min: 0.000001, advanced: true },
|
||
{ key: "target_subcooling_k", label: "Target subcooling", kind: "number", unit: "K", default: 3.0, section: "Operating model", min: 0.0 },
|
||
{
|
||
key: "emergent_pressure",
|
||
label: "Solve condensing pressure",
|
||
kind: "boolean",
|
||
default: true,
|
||
section: "Solved-cycle mode",
|
||
description:
|
||
"ON: +1 outlet-closure residual pins h_out to target subcooling so P_cond emerges from the secondary balance.",
|
||
},
|
||
{
|
||
key: "correlation",
|
||
label: "Two-phase correlation",
|
||
kind: "string",
|
||
default: "Longo2004",
|
||
section: "Heat-transfer model",
|
||
options: [
|
||
{ value: "Longo2004", label: "Longo 2004" },
|
||
{ value: "Shah1979", label: "Shah 1979" },
|
||
{ value: "Shah2021", label: "Shah 2021" },
|
||
],
|
||
},
|
||
{
|
||
key: "dp_correlation",
|
||
label: "Pressure-drop correlation",
|
||
kind: "string",
|
||
default: "SimplifiedChannel",
|
||
section: "Pressure drop",
|
||
description:
|
||
"Channel friction on both hot and cold sides (independent of HTC). Default SimplifiedChannel; Martin1996 uses chevron angle.",
|
||
options: [
|
||
{ value: "SimplifiedChannel", label: "Simplified channel (default)" },
|
||
{ value: "Martin1996", label: "Martin 1996 (chevron)" },
|
||
],
|
||
},
|
||
{ key: "ua", label: "UA override", kind: "number", unit: "W/K", section: "Calibration", min: 0.0, advanced: true },
|
||
{
|
||
key: "z_ua",
|
||
label: "Z_UA (UA factor)",
|
||
kind: "number",
|
||
default: 1.0,
|
||
section: "Calibration",
|
||
min: 0.000001,
|
||
fixable: true,
|
||
defaultFixed: true,
|
||
actuatorFactor: "z_ua",
|
||
freeMin: 0.2,
|
||
freeMax: 3.0,
|
||
},
|
||
{
|
||
key: "z_dp",
|
||
label: "Z_dP (pressure-drop factor)",
|
||
kind: "number",
|
||
default: 1.0,
|
||
section: "Calibration",
|
||
min: 0.000001,
|
||
fixable: true,
|
||
defaultFixed: true,
|
||
actuatorFactor: "z_dp",
|
||
freeMin: 0.2,
|
||
freeMax: 3.0,
|
||
},
|
||
],
|
||
},
|
||
{
|
||
type: "FloodedEvaporator",
|
||
label: "Flooded Evaporator",
|
||
category: "Heat Exchangers",
|
||
description: "Évaporateur noyé (shell & tube). Sortie vapeur saturée par défaut.",
|
||
help:
|
||
"Rôle : évaporateur noyé — le frigorigène bout dans la calandre, l’eau/glycol dans les tubes.\n\n" +
|
||
"Ports : inlet/outlet frigo · secondary_in/out eau.\n\n" +
|
||
"Mode machine : relier BrineSource → secondary_in → secondary_out → BrineSink.\n" +
|
||
"Mode rating : renseigner T et débit secondaires sans câbler l’eau.\n\n" +
|
||
"Calibration : onglet Calibration — Fixed sur SST + Fixed décoché sur Z_UA (défaut Z_UA = 1).\n\n" +
|
||
"quality_control : laisser OFF sauf modèle de recirculation spécialisé.",
|
||
docSlug: "flooded-evaporator",
|
||
ports: ["inlet", "outlet", "secondary_inlet", "secondary_outlet"],
|
||
color: "#06b6d4",
|
||
params: [
|
||
{ key: "manufacturer", label: "Manufacturer", kind: "string", default: "", section: "Identification" },
|
||
{ key: "model", label: "Model / reference", kind: "string", default: "", section: "Identification" },
|
||
{ key: "refrigerant", label: "Refrigerant", kind: "string", default: "R134a", section: "Fluids" },
|
||
{ key: "secondary_fluid", label: "Secondary fluid", kind: "string", default: "Water", section: "Fluids" },
|
||
{ key: "ua", label: "UA", kind: "number", unit: "W/K", default: 8000.0, required: true, section: "Thermal model", min: 0.0, sweepable: true, sweepGroup: "thermal" },
|
||
{
|
||
key: "secondary_rated_pressure_drop_pa",
|
||
label: "Tube-side water design ΔP",
|
||
kind: "number",
|
||
unit: "Pa",
|
||
default: 40000,
|
||
section: "Secondary hydraulics",
|
||
min: 0.0,
|
||
description:
|
||
"Water/brine ΔP through the tubes at rated ṁ (quadratic). 0 = isobaric (legacy).",
|
||
},
|
||
{
|
||
key: "secondary_rated_m_flow_kg_s",
|
||
label: "Tube-side water design ṁ",
|
||
kind: "number",
|
||
unit: "kg/s",
|
||
default: 0.55,
|
||
section: "Secondary hydraulics",
|
||
min: 0.0,
|
||
},
|
||
{
|
||
key: "z_ua",
|
||
label: "Z_UA (UA factor)",
|
||
kind: "number",
|
||
default: 1.0,
|
||
section: "Calibration",
|
||
min: 0.000001,
|
||
fixable: true,
|
||
defaultFixed: true,
|
||
actuatorFactor: "z_ua",
|
||
freeMin: 0.2,
|
||
freeMax: 3.0,
|
||
description: "Fixed = figé. Décocher Fixed = le solveur ajuste Z_UA.",
|
||
},
|
||
{
|
||
key: "z_dp",
|
||
label: "Z_dP (pressure-drop factor)",
|
||
kind: "number",
|
||
default: 1.0,
|
||
section: "Calibration",
|
||
min: 0.000001,
|
||
advanced: true,
|
||
fixable: true,
|
||
defaultFixed: true,
|
||
actuatorFactor: "z_dp",
|
||
freeMin: 0.2,
|
||
freeMax: 3.0,
|
||
},
|
||
{
|
||
key: "quality_control",
|
||
label: "Quality control residual",
|
||
kind: "boolean",
|
||
default: false,
|
||
section: "Solved-cycle mode",
|
||
description:
|
||
"FIX: adds q_out − target residual (+1 equation). Over-constrains a closed cycle unless you FREE an actuator (EXV/level). Prefer OFF for compressor suction.",
|
||
},
|
||
{
|
||
key: "target_quality",
|
||
label: "Outlet vapour quality target",
|
||
kind: "number",
|
||
default: 0.7,
|
||
section: "Solved-cycle mode",
|
||
min: 0.0,
|
||
max: 1.0,
|
||
description: "Only used when quality_control is ON. Legacy flooded recirculation target — not physical for dry suction.",
|
||
},
|
||
{
|
||
key: "secondary_inlet_temp_c",
|
||
label: "Secondary inlet T (rating only)",
|
||
kind: "number",
|
||
unit: "°C",
|
||
default: 12.0,
|
||
section: "Secondary side (rating)",
|
||
description: "Rating-mode scalar. For system solves, impose T via BrineSource on secondary_inlet instead.",
|
||
},
|
||
{
|
||
key: "secondary_mass_flow_kg_s",
|
||
label: "Secondary mass flow (rating only)",
|
||
kind: "number",
|
||
unit: "kg/s",
|
||
default: 1.5,
|
||
section: "Secondary side (rating)",
|
||
min: 0.0,
|
||
description: "Rating-mode scalar. For system solves, set ṁ on BrineSource.",
|
||
},
|
||
{
|
||
key: "secondary_cp_j_per_kgk",
|
||
label: "Secondary cp (rating only)",
|
||
kind: "number",
|
||
unit: "J/kg·K",
|
||
default: 4186.0,
|
||
section: "Secondary side (rating)",
|
||
min: 0.0,
|
||
advanced: true,
|
||
},
|
||
{
|
||
key: "ua_mode",
|
||
label: "UA mode",
|
||
kind: "string",
|
||
default: "fixed",
|
||
section: "Thermal model",
|
||
options: [
|
||
{ value: "fixed", label: "Fixed UA" },
|
||
{ value: "cooper", label: "Cooper pool boiling" },
|
||
],
|
||
description: "cooper = outer-loop UA from Cooper + Palen (Picard).",
|
||
},
|
||
{
|
||
key: "area_ref_m2",
|
||
label: "Refrigerant HTA",
|
||
kind: "number",
|
||
unit: "m²",
|
||
default: 20.0,
|
||
section: "Pool boiling",
|
||
advanced: true,
|
||
},
|
||
{
|
||
key: "area_sec_m2",
|
||
label: "Secondary HTA",
|
||
kind: "number",
|
||
unit: "m²",
|
||
default: 18.0,
|
||
section: "Pool boiling",
|
||
advanced: true,
|
||
},
|
||
],
|
||
},
|
||
{
|
||
type: "HeatExchanger",
|
||
label: "Generic Heat Exchanger",
|
||
category: "Heat Exchangers",
|
||
description: "Strict four-port two-fluid heat exchanger. Every side is a real solver edge.",
|
||
ports: ["hot_inlet", "hot_outlet", "cold_inlet", "cold_outlet"],
|
||
color: "#8b5cf6",
|
||
params: [
|
||
{ key: "manufacturer", label: "Manufacturer", kind: "string", default: "", section: "Identification" },
|
||
{ key: "model", label: "Model / reference", kind: "string", default: "", section: "Identification" },
|
||
{ key: "ua", label: "UA", kind: "number", unit: "W/K", default: 3000.0, required: true, section: "Thermal model", min: 0.0, sweepable: true, sweepGroup: "thermal" },
|
||
{ key: "hot_fluid_id", label: "Hot-side fluid", kind: "string", default: "Water", section: "Fluids" },
|
||
{ key: "cold_fluid_id", label: "Cold-side fluid", kind: "string", default: "Air", section: "Fluids" },
|
||
{ key: "hot_humidity_ratio", label: "Hot-side humidity ratio", kind: "number", unit: "kg/kg", default: 0.0, section: "Psychrometrics", min: 0.0, advanced: true },
|
||
{ key: "cold_humidity_ratio", label: "Cold-side humidity ratio", kind: "number", unit: "kg/kg", default: 0.01, section: "Psychrometrics", min: 0.0, advanced: true },
|
||
],
|
||
},
|
||
|
||
// ── Expansion ──────────────────────────────────────────────────────────
|
||
{
|
||
type: "IsenthalpicExpansionValve",
|
||
label: "Expansion Valve (EXV)",
|
||
category: "Expansion",
|
||
description: "Détendeur isenthalpique (EXV).",
|
||
help:
|
||
"Rôle : fait chuter la pression frigo (h constant).\n\n" +
|
||
"Ports : inlet (liquide HP) · outlet (biphasique BP).\n\n" +
|
||
"Sans orifice_kv : isenthalpique seul — opening n’a aucun effet physique.\n" +
|
||
"Avec orifice_kv : ṁ = Kv·opening·√(2·ρ·ΔP). Opening Fixed (défaut) = paramètre ; " +
|
||
"Free = inconnue (régulation / SaturatedController).\n" +
|
||
"Orifice Fixed → le compresseur lâche la loi de ṁ (débit métré par l’EXV).\n" +
|
||
"t_evap_k : guess / mode pression fixée selon le cycle.",
|
||
docSlug: "isenthalpic-expansion-valve",
|
||
ports: ["inlet", "outlet"],
|
||
color: "#10b981",
|
||
params: [
|
||
{ key: "t_evap_k", label: "Evaporating temp (K)", kind: "number", unit: "K", default: 275.15 },
|
||
{
|
||
key: "orifice_kv",
|
||
label: "Orifice Kv",
|
||
kind: "number",
|
||
unit: "m²",
|
||
section: "Orifice",
|
||
description:
|
||
"Capacité d’orifice. Obligatoire pour que opening change le débit. Typique ~1e-7…1e-5 m².",
|
||
},
|
||
{
|
||
key: "opening",
|
||
label: "Valve opening (0–1)",
|
||
kind: "number",
|
||
default: 1.0,
|
||
min: 0,
|
||
max: 1,
|
||
section: "Orifice",
|
||
fixable: true,
|
||
defaultFixed: true,
|
||
description: "Nécessite orifice_kv. Fixed = impose opening ; Free = inconnue solver.",
|
||
sweepable: true,
|
||
sweepGroup: "machine",
|
||
},
|
||
],
|
||
},
|
||
{
|
||
type: "ExpansionValve",
|
||
label: "Expansion Valve (basic)",
|
||
category: "Expansion",
|
||
description: "Physical EXV/TXV with selectable flow model (orifice, Cd·A, Eames).",
|
||
ports: ["inlet", "outlet"],
|
||
color: "#10b981",
|
||
params: [
|
||
{ key: "fluid", label: "Fluid", kind: "string", default: "R134a", required: true },
|
||
{ key: "opening", label: "Opening (0–1)", kind: "number", default: 1.0, sweepable: true, sweepGroup: "machine" },
|
||
{
|
||
key: "flow_model",
|
||
label: "Flow model",
|
||
kind: "string",
|
||
default: "orifice",
|
||
options: [
|
||
{ value: "orifice", label: "Isenthalpic orifice" },
|
||
{ value: "exv", label: "EXV Cd·A" },
|
||
{ value: "txv", label: "TXV Eames" },
|
||
],
|
||
},
|
||
{ key: "beta_m2", label: "β / orifice area", kind: "number", unit: "m²", default: 1e-6, advanced: true },
|
||
{ key: "cd", label: "Discharge Cd", kind: "number", default: 0.7, advanced: true },
|
||
{ key: "area_max_m2", label: "A_max", kind: "number", unit: "m²", default: 2e-6, advanced: true },
|
||
{ key: "bulb_pressure_pa", label: "TXV bulb P", kind: "number", unit: "Pa", default: 400000, advanced: true },
|
||
],
|
||
},
|
||
{
|
||
type: "CapillaryTube",
|
||
label: "Capillary Tube",
|
||
category: "Expansion",
|
||
description: "Adiabatic capillary (segmented ΔP, isenthalpic).",
|
||
help: "Diamètre / longueur / segments. Corrélation DP MSH par défaut.",
|
||
ports: ["inlet", "outlet"],
|
||
color: "#059669",
|
||
params: [
|
||
{ key: "diameter_m", label: "Inner diameter", kind: "number", unit: "m", default: 0.001, required: true },
|
||
{ key: "length_m", label: "Length", kind: "number", unit: "m", default: 2.0, required: true },
|
||
{ key: "n_segments", label: "Segments", kind: "number", default: 20, advanced: true },
|
||
],
|
||
},
|
||
{
|
||
type: "ReversingValve",
|
||
label: "Reversing Valve (4-way)",
|
||
category: "Expansion",
|
||
description: "Four-way reversing valve for heat-pump mode switch.",
|
||
ports: ["inlet", "outlet"],
|
||
color: "#0d9488",
|
||
params: [
|
||
{
|
||
key: "mode",
|
||
label: "Mode",
|
||
kind: "string",
|
||
default: "cooling",
|
||
options: [
|
||
{ value: "cooling", label: "Cooling" },
|
||
{ value: "heating", label: "Heating" },
|
||
],
|
||
},
|
||
{ key: "pressure_drop_pa", label: "Pressure drop", kind: "number", unit: "Pa", default: 5000 },
|
||
],
|
||
},
|
||
{
|
||
type: "BypassValve",
|
||
label: "Bypass Valve",
|
||
category: "Expansion",
|
||
description: "Proportional bypass valve.",
|
||
ports: ["inlet", "outlet"],
|
||
color: "#14b8a6",
|
||
params: [
|
||
{ key: "opening", label: "Opening (0–1)", kind: "number", default: 0.5, sweepable: true, sweepGroup: "machine" },
|
||
],
|
||
},
|
||
|
||
// ── Piping (Modelica/TIL media: green ref · blue water · yellow air) ────
|
||
{
|
||
type: "RefrigerantPipe",
|
||
label: "Pipe — refrigerant",
|
||
category: "Piping",
|
||
description: "Ligne frigorifique (Darcy–Weisbach). Glisser sur une ligne verte pour l’insérer.",
|
||
help:
|
||
"Conduit frigorigène. Dépose-le sur une connexion verte pour couper la ligne et l’insérer automatiquement.\n" +
|
||
"CLI type: RefrigerantPipe (alias Pipe).\n" +
|
||
"Design ΔP = 0 (défaut) → perte Darcy–Weisbach depuis L/D + ṁ.\n" +
|
||
"Design ΔP > 0 → impose cette chute constante (ignore L/D pour ΔP).",
|
||
ports: ["inlet", "outlet"],
|
||
color: "#2e7d32",
|
||
params: [
|
||
{ key: "fluid", label: "Fluid", kind: "string", default: "R134a", section: "Medium" },
|
||
{ key: "length_m", label: "Length", kind: "number", unit: "m", default: 3.0, required: true, section: "Geometry" },
|
||
{ key: "diameter_m", label: "Inner diameter", kind: "number", unit: "m", default: 0.012, required: true, section: "Geometry" },
|
||
{
|
||
key: "pressure_drop_pa",
|
||
label: "Design ΔP (0 = Darcy)",
|
||
kind: "number",
|
||
unit: "Pa",
|
||
default: 0,
|
||
section: "Hydraulics",
|
||
description: "0 = ΔP Darcy depuis géométrie + débit. >0 = ΔP imposé constant.",
|
||
},
|
||
{ key: "roughness_m", label: "Roughness", kind: "number", unit: "m", default: 0.0000015, section: "Geometry", advanced: true },
|
||
{ key: "density_kg_m3", label: "Density (design)", kind: "number", unit: "kg/m³", default: 1140, section: "Properties", advanced: true },
|
||
{ key: "viscosity_pa_s", label: "Viscosity (design)", kind: "number", unit: "Pa·s", default: 0.0002, section: "Properties", advanced: true },
|
||
],
|
||
},
|
||
{
|
||
type: "WaterPipe",
|
||
label: "Pipe — water / brine",
|
||
category: "Piping",
|
||
description: "Tuyauterie eau/glycol. Glisser sur une ligne bleue pour l’insérer.",
|
||
help:
|
||
"Conduit caloporteur. Dépose-le sur une connexion bleue (BrineSource ↔ HX) pour l’insérer dans le circuit.\n" +
|
||
"Design ΔP = 0 → Darcy L/D ; >0 → ΔP imposé.",
|
||
ports: ["inlet", "outlet"],
|
||
color: "#1565c0",
|
||
params: [
|
||
{ key: "fluid", label: "Fluid", kind: "string", default: "Water", section: "Medium" },
|
||
{ key: "length_m", label: "Length", kind: "number", unit: "m", default: 5.0, required: true, section: "Geometry" },
|
||
{ key: "diameter_m", label: "Inner diameter", kind: "number", unit: "m", default: 0.025, required: true, section: "Geometry" },
|
||
{
|
||
key: "pressure_drop_pa",
|
||
label: "Design ΔP (0 = Darcy)",
|
||
kind: "number",
|
||
unit: "Pa",
|
||
default: 0,
|
||
section: "Hydraulics",
|
||
description: "0 = ΔP Darcy depuis géométrie + débit. >0 = ΔP imposé constant.",
|
||
},
|
||
{ key: "roughness_m", label: "Roughness", kind: "number", unit: "m", default: 0.000045, section: "Geometry", advanced: true },
|
||
{ key: "density_kg_m3", label: "Density", kind: "number", unit: "kg/m³", default: 998, section: "Properties", advanced: true },
|
||
{ key: "viscosity_pa_s", label: "Viscosity", kind: "number", unit: "Pa·s", default: 0.001, section: "Properties", advanced: true },
|
||
],
|
||
},
|
||
{
|
||
type: "AirDuct",
|
||
label: "Duct — air",
|
||
category: "Piping",
|
||
description: "Gaine d’air. Glisser sur une ligne jaune pour l’insérer.",
|
||
help:
|
||
"Conduit air. Dépose-le sur une connexion jaune (AirSource / Fan / coil air) pour l’insérer.\n" +
|
||
"Design ΔP = 0 → Darcy L/D ; >0 → ΔP imposé.",
|
||
ports: ["inlet", "outlet"],
|
||
color: "#f9a825",
|
||
params: [
|
||
{ key: "fluid", label: "Fluid", kind: "string", default: "Air", section: "Medium" },
|
||
{ key: "length_m", label: "Length", kind: "number", unit: "m", default: 5.0, required: true, section: "Geometry" },
|
||
{ key: "diameter_m", label: "Hydraulic diameter", kind: "number", unit: "m", default: 0.2, required: true, section: "Geometry" },
|
||
{
|
||
key: "pressure_drop_pa",
|
||
label: "Design ΔP (0 = Darcy)",
|
||
kind: "number",
|
||
unit: "Pa",
|
||
default: 0,
|
||
section: "Hydraulics",
|
||
description: "0 = ΔP Darcy depuis géométrie + débit. >0 = ΔP imposé constant.",
|
||
},
|
||
{ key: "roughness_m", label: "Roughness", kind: "number", unit: "m", default: 0.00015, section: "Geometry", advanced: true },
|
||
{ key: "density_kg_m3", label: "Density", kind: "number", unit: "kg/m³", default: 1.2, section: "Properties", advanced: true },
|
||
{ key: "viscosity_pa_s", label: "Viscosity", kind: "number", unit: "Pa·s", default: 0.000018, section: "Properties", advanced: true },
|
||
],
|
||
},
|
||
{
|
||
type: "Pipe",
|
||
label: "Pipe (generic)",
|
||
category: "Piping",
|
||
description: "Legacy generic pipe — prefer medium-specific pipes above.",
|
||
ports: ["inlet", "outlet"],
|
||
color: "#64748b",
|
||
params: [
|
||
{ key: "fluid", label: "Fluid", kind: "string", default: "R134a" },
|
||
{ key: "length_m", label: "Length (m)", kind: "number", unit: "m", default: 10.0, required: true },
|
||
{ key: "diameter_m", label: "Diameter (m)", kind: "number", unit: "m", default: 0.022, required: true },
|
||
{ key: "roughness_m", label: "Roughness (m)", kind: "number", unit: "m", default: 0.0000015 },
|
||
],
|
||
},
|
||
{
|
||
type: "Drum",
|
||
label: "Liquid-Vapor Separator",
|
||
category: "Piping",
|
||
description: "Phase separator / accumulator.",
|
||
ports: ["inlet", "liquid_outlet", "vapor_outlet"],
|
||
color: "#94a3b8",
|
||
params: [],
|
||
},
|
||
{
|
||
type: "FlowSplitter",
|
||
label: "Flow Splitter",
|
||
category: "Piping",
|
||
description: "Splits a flow into two branches.",
|
||
ports: ["inlet", "outlet_a", "outlet_b"],
|
||
color: "#94a3b8",
|
||
params: [
|
||
{ key: "split_ratio", label: "Split ratio (outlet_a)", kind: "number", default: 0.5 },
|
||
],
|
||
},
|
||
{
|
||
type: "FlowMerger",
|
||
label: "Flow Merger",
|
||
category: "Piping",
|
||
description: "Merges two flows into one.",
|
||
ports: ["inlet_a", "inlet_b", "outlet"],
|
||
color: "#94a3b8",
|
||
params: [],
|
||
},
|
||
|
||
// ── Hydraulics ─────────────────────────────────────────────────────────
|
||
{
|
||
type: "Pump",
|
||
label: "Pump",
|
||
category: "Hydraulics",
|
||
description: "Pompe — impose ΔP/courbe (esprit Modelica.Fluid.Machines).",
|
||
help:
|
||
"Modelica: une pompe prescrit ṁ ou ΔP via sa courbe — ne pas aussi Fixed ṁ " +
|
||
"sur un MassFlowSource de la même branche (surcontraint).",
|
||
ports: ["inlet", "outlet"],
|
||
color: "#a855f7",
|
||
params: [
|
||
{ key: "head_coeffs", label: "Head curve (a0,a1,a2)", kind: "string", unit: "m", default: "30,-10,-50", required: true },
|
||
{ key: "eff_coeffs", label: "Efficiency curve (a0,a1,a2)", kind: "string", default: "0.5,0.3,-0.5", required: true },
|
||
{ key: "density_kg_m3", label: "Fluid density (kg/m³)", kind: "number", unit: "kg/m³", default: 1000.0 },
|
||
],
|
||
},
|
||
{
|
||
type: "Fan",
|
||
label: "Fan",
|
||
category: "Hydraulics",
|
||
description: "Edge-coupled fan for air-side loops; pressure rise and shaft heat are solved on live edges.",
|
||
ports: ["inlet", "outlet"],
|
||
color: "#d946ef",
|
||
params: [
|
||
{ key: "fluid", label: "Fluid", kind: "string", default: "Air" },
|
||
{ key: "speed_ratio", label: "Speed ratio", kind: "number", default: 1.0, sweepable: true, sweepGroup: "machine" },
|
||
{ key: "air_density_kg_m3", label: "Air density", kind: "number", unit: "kg/m³", default: 1.204 },
|
||
{ key: "design_flow_m3_s", label: "Design flow", kind: "number", unit: "m³/s", default: 0.83, required: true },
|
||
{ key: "curve_p0", label: "Curve p0", kind: "number", unit: "Pa", default: 250.0 },
|
||
{ key: "curve_p1", label: "Curve p1", kind: "number", default: 0.0 },
|
||
{ key: "curve_p2", label: "Curve p2", kind: "number", default: -20.0 },
|
||
{ key: "eff_e0", label: "Efficiency e0", kind: "number", default: 0.65 },
|
||
{ key: "eff_e1", label: "Efficiency e1", kind: "number", default: 0.0 },
|
||
{ key: "eff_e2", label: "Efficiency e2", kind: "number", default: 0.0 },
|
||
{
|
||
key: "drive_chain",
|
||
label: "Wire-to-air drive chain",
|
||
kind: "boolean",
|
||
default: false,
|
||
description: "Apply η_VFD × η_motor on top of fan efficiency (Bernier–Bourret).",
|
||
},
|
||
],
|
||
},
|
||
{
|
||
type: "FreeCoolingExchanger",
|
||
label: "Free Cooling Exchanger",
|
||
category: "Heat Exchangers",
|
||
description: "Water–water free-cooling HX (effectiveness / UA).",
|
||
ports: ["cold_inlet", "cold_outlet", "hot_inlet", "hot_outlet"],
|
||
color: "#7c3aed",
|
||
params: [
|
||
{ key: "ua", label: "UA", kind: "number", unit: "W/K", default: 10000.0, required: true, sweepable: true, sweepGroup: "thermal" },
|
||
{ key: "effectiveness", label: "Effectiveness", kind: "number", default: 0.85 },
|
||
],
|
||
},
|
||
|
||
// ── Boundaries ─────────────────────────────────────────────────────────
|
||
{
|
||
type: "RefrigerantSource",
|
||
label: "Refrigerant Source",
|
||
category: "Boundaries",
|
||
description: "Fixed-state refrigerant boundary.",
|
||
ports: ["outlet"],
|
||
color: "#f1f5f9",
|
||
params: [
|
||
{ key: "pressure_bar", label: "Pressure (bar)", kind: "number", unit: "bar", default: 10.0, required: true },
|
||
{ key: "temperature_c", label: "Temperature (°C)", kind: "number", unit: "°C", default: 40.0 },
|
||
],
|
||
},
|
||
{
|
||
type: "RefrigerantSink",
|
||
label: "Refrigerant Sink",
|
||
category: "Boundaries",
|
||
description: "Fixed-pressure refrigerant boundary.",
|
||
ports: ["inlet"],
|
||
color: "#f1f5f9",
|
||
params: [
|
||
{ key: "pressure_bar", label: "Pressure (bar)", kind: "number", unit: "bar", default: 4.0, required: true },
|
||
],
|
||
},
|
||
{
|
||
type: "BrineSource",
|
||
label: "Brine / Glycol Source",
|
||
category: "Boundaries",
|
||
description: "Modelica MassFlowSource_T / Boundary_pT.",
|
||
help:
|
||
"Modelica.Fluid.Sources (doc.modelica.org):\n" +
|
||
"• MassFlowSource_T — Fixed T + Fixed ṁ, Free P (défaut)\n" +
|
||
"• Boundary_pT — Fixed P + Fixed T, Free ṁ\n" +
|
||
"Jamais Fixed P et Fixed ṁ ensemble.\n" +
|
||
"Ancre P = Sink. Double Fixed P seulement avec ΔP hydraulique (pipe).\n" +
|
||
"T_out imposé : Free ṁ ici + Fixed T_out sur le Sink.",
|
||
docSlug: "boundaries",
|
||
ports: ["outlet"],
|
||
color: "#e0f2fe",
|
||
params: [
|
||
{ key: "fluid", label: "Fluid", kind: "string", default: "Water" },
|
||
{
|
||
key: "p_set_bar",
|
||
label: "Pressure setpoint",
|
||
kind: "number",
|
||
unit: "bar",
|
||
default: 2.0,
|
||
required: true,
|
||
fixable: true,
|
||
defaultFixed: false,
|
||
description: "Free (défaut MassFlowSource_T). Fixed ⇒ mode Boundary_pT (Free ṁ).",
|
||
},
|
||
{
|
||
key: "t_set_c",
|
||
label: "Temperature setpoint",
|
||
kind: "number",
|
||
unit: "°C",
|
||
default: 12.0,
|
||
required: true,
|
||
fixable: true,
|
||
defaultFixed: true,
|
||
sweepable: true,
|
||
sweepGroup: "boundaries",
|
||
},
|
||
{
|
||
key: "m_flow_kg_s",
|
||
label: "Mass flow",
|
||
kind: "number",
|
||
unit: "kg/s",
|
||
default: 0.5,
|
||
required: true,
|
||
fixable: true,
|
||
defaultFixed: true,
|
||
description: "Fixed ⇒ Free P auto. Free ⇒ ṁ issu du bilan (avec Fixed T_out au Sink).",
|
||
sweepable: true,
|
||
sweepGroup: "boundaries",
|
||
},
|
||
],
|
||
},
|
||
{
|
||
type: "BrineSink",
|
||
label: "Brine / Glycol Sink",
|
||
category: "Boundaries",
|
||
description: "Modelica Boundary_p — ancre de pression.",
|
||
help:
|
||
"Ancre P du circuit (Boundary_p). Fixed P par défaut.\n" +
|
||
"Fixed T_out ⇒ Free ṁ sur la Source (pas de Fixed ṁ en même temps).",
|
||
docSlug: "boundaries",
|
||
ports: ["inlet"],
|
||
color: "#e0f2fe",
|
||
params: [
|
||
{ key: "fluid", label: "Fluid", kind: "string", default: "Water" },
|
||
{
|
||
key: "p_back_bar",
|
||
label: "Back pressure",
|
||
kind: "number",
|
||
unit: "bar",
|
||
default: 2.0,
|
||
required: true,
|
||
fixable: true,
|
||
defaultFixed: true,
|
||
},
|
||
{
|
||
key: "t_set_c",
|
||
label: "Outlet temperature",
|
||
kind: "number",
|
||
unit: "°C",
|
||
default: 7.0,
|
||
fixable: true,
|
||
defaultFixed: false,
|
||
description: "Fixed ON ⇒ impose h_out. Libère ṁ sur la Source.",
|
||
sweepable: true,
|
||
sweepGroup: "boundaries",
|
||
},
|
||
],
|
||
},
|
||
{
|
||
type: "AirSource",
|
||
label: "Air Source",
|
||
category: "Boundaries",
|
||
description: "Modelica MassFlowSource_T (air).",
|
||
help:
|
||
"MassFlowSource_T : Fixed T + Fixed ṁ, Free P (défaut).\n" +
|
||
"Boundary_pT : Fixed P + Free ṁ. Jamais Fixed P+ṁ ensemble.",
|
||
ports: ["outlet"],
|
||
color: "#f0fdf4",
|
||
params: [
|
||
{
|
||
key: "p_set_bar",
|
||
label: "Pressure setpoint",
|
||
kind: "number",
|
||
unit: "bar",
|
||
default: 1.01325,
|
||
required: true,
|
||
fixable: true,
|
||
defaultFixed: false,
|
||
},
|
||
{
|
||
key: "t_dry_c",
|
||
label: "Dry-bulb temperature",
|
||
kind: "number",
|
||
unit: "°C",
|
||
default: 20.0,
|
||
required: true,
|
||
fixable: true,
|
||
defaultFixed: true,
|
||
sweepable: true,
|
||
sweepGroup: "boundaries",
|
||
},
|
||
{ key: "rh", label: "Relative humidity", kind: "number", unit: "%", default: 50.0 },
|
||
{
|
||
key: "m_flow_kg_s",
|
||
label: "Mass flow",
|
||
kind: "number",
|
||
unit: "kg/s",
|
||
default: 1.0,
|
||
required: true,
|
||
fixable: true,
|
||
defaultFixed: true,
|
||
sweepable: true,
|
||
sweepGroup: "boundaries",
|
||
},
|
||
],
|
||
},
|
||
{
|
||
type: "AirSink",
|
||
label: "Air Sink",
|
||
category: "Boundaries",
|
||
description: "Modelica Boundary_p (air) — ancre P.",
|
||
ports: ["inlet"],
|
||
color: "#f0fdf4",
|
||
params: [
|
||
{
|
||
key: "p_back_bar",
|
||
label: "Back pressure",
|
||
kind: "number",
|
||
unit: "bar",
|
||
default: 1.01325,
|
||
required: true,
|
||
fixable: true,
|
||
defaultFixed: true,
|
||
},
|
||
{
|
||
key: "t_back_c",
|
||
label: "Return temperature",
|
||
kind: "number",
|
||
unit: "°C",
|
||
default: 25.0,
|
||
fixable: true,
|
||
defaultFixed: false,
|
||
},
|
||
],
|
||
},
|
||
|
||
// ── Generic ────────────────────────────────────────────────────────────
|
||
{
|
||
type: "Placeholder",
|
||
label: "Placeholder",
|
||
category: "Generic",
|
||
description: "Generic placeholder with configurable equation count.",
|
||
ports: ["inlet", "outlet"],
|
||
color: "#e2e8f0",
|
||
params: [
|
||
{ key: "n_equations", label: "Number of equations", kind: "number", default: 2, required: true },
|
||
],
|
||
},
|
||
];
|
||
|
||
export const COMPONENT_BY_TYPE: Record<string, ComponentMeta> = Object.fromEntries(
|
||
COMPONENTS.map((c) => [c.type, c]),
|
||
);
|
||
|
||
/** Build the default parameter values for a component type. */
|
||
export function defaultParams(type: string): Record<string, number | string | boolean> {
|
||
const meta = COMPONENT_BY_TYPE[type];
|
||
if (!meta) return {};
|
||
const out: Record<string, number | string | boolean> = {};
|
||
for (const p of meta.params) {
|
||
if (p.default !== undefined) out[p.key] = p.default;
|
||
// Seed Fixed flags so Free/Fixed state is explicit after drop
|
||
if (p.fixable) {
|
||
out[fixedFlagKey(p.key)] = p.defaultFixed !== false;
|
||
}
|
||
}
|
||
return out;
|
||
}
|
||
|
||
/**
|
||
* Value shown / used for a param: stored value, else meta.default.
|
||
* Ensures Z_UA=1 etc. always appear even if an old node lacks the key.
|
||
*/
|
||
export function effectiveParamValue(
|
||
params: Record<string, number | string | boolean | undefined>,
|
||
meta: ParamMeta,
|
||
): number | string | boolean | undefined {
|
||
const v = params[meta.key];
|
||
if (v !== undefined && v !== "") return v;
|
||
return meta.default;
|
||
}
|
||
|
||
/** Merge missing defaults into a params object (non-destructive for existing keys). */
|
||
export function mergeDefaultParams(
|
||
type: string,
|
||
params: Record<string, number | string | boolean>,
|
||
): Record<string, number | string | boolean> {
|
||
const defaults = defaultParams(type);
|
||
return { ...defaults, ...params };
|
||
}
|