REST API 与 MCP 集成
计算器 REST API:请求、结果与诊断
六种翅片盘管引擎、八条计算路由和两条查询/健康路由的当前契约,附本地纯内存验证的完整合成示例。
修订日期
1. 访问条件与路由清单
使用部署的 ExCoil 站点源地址和下列准确路径。POST 请求发送 Authorization: Bearer <REST_API_KEY> 和 Content-Type: application/json。REST 密钥以 exk_ 开头;仅在服务端保存,勿写入日志、仓库或浏览器代码。需要状态为 active 或 trialing 的 Enterprise 或 Manufacturer 订阅。Free/Professional 可在应用内计算,并不代表有 REST 权限。
密钥存在权限列表时,计算与 /refrigerants 检查 calc:read。null 列表不限制权限,空列表不授予权限,* 可通过检查。/health 需要身份验证但不检查 calc:read。所有这些请求都消耗密钥限额。本 API 不提供 Shell & Tube、湿空气计算、项目写入、PDF/CAD 或制造导出。MCP 使用独立令牌与 /api/mcp,且仅限 Manufacturer。
| 方法 | 路径 | JSON 根字段 |
|---|---|---|
| POST | /api/v1/calculate/dx-evaporator | air, coil, ref, calib |
| POST | /api/v1/calculate/dx-evaporator/balanced | inputs, options? |
| POST | /api/v1/calculate/dx-condenser | air, coil, ref, calib |
| POST | /api/v1/calculate/dx-condenser/balanced | air, coil, ref, calib |
| POST | /api/v1/calculate/chilled-water | air, water, coil, hydraulic, calib |
| POST | /api/v1/calculate/hot-water | air, water, coil, hydraulic, calib |
| POST | /api/v1/calculate/steam-coil | air, steam, coil, hydraulic, calib |
| POST | /api/v1/calculate/dry-cooler | air, fluid, coil, hydraulic, calib |
| GET | /api/v1/refrigerants | — |
| GET | /api/v1/health | — |
2. 使用 SI 输入,不要发送界面表单对象
下方示例分别列出 request 与 response;只发送 request 的内容,不发送外层对象或 response。数值是合成演示工况,不是推荐设计。每个示例均通过当前输入 schema 和纯内存引擎计算。REST 路由并不执行 tRPC/MCP 使用的 Zod schema,仅在浅层对象/制冷剂检查后把请求交给引擎。不要假定存在逐字段错误、自动单位换算或 schema 默认值填充。
除干冷器外,air 使用 Vdot_m3_s、T_in_C、RH_in、P_Pa,分别为 m³/s、干球 °C、0–1 相对湿度及当地绝对大气压 Pa。冷凝器 RH_in 可省略(引擎默认 0.5)。几何字段是 coil,而非 geometry:height_m、width_m、Pt_m、Pl_m、Do_m、wall_m、fin_m 均为米;rows 是正整数;fpi 仍为每英寸翅片数;tube_k/fin_k 为 W/(m·K),freeAreaRatio 为比例。尺寸与导热系数需为正,Do_m > 2·wall_m,管间距需大于 Do_m。DX 的 tubesPerRow 将有效高度固定为 tubesPerRow × Pt_m。水/蒸汽/干冷器的 hydraulic.tubeCountOverride 是每排管数,不是总管数。
finType 可为 plain、wavy、louver、slit,冷凝器仅接受前三项。水/蒸汽/干冷器 coil 还含 tubeMat、finMat;导热系数需明确提供。calib 按模块填写,不要放入 options。segments 是可选数值积分分辨率,不是实际管数。通常 schema 的 freeAreaRatio 范围为 0.1–0.9;冷凝器 schema 允许 0–1,但引擎要求 >0 且 ≤1。DX 的 f_maldistribution 要求 >0 且 ≤1。必须另行验证物理关系,schema 通过不等于工况可行。
可选 circuitryPD 在 DX 中位于 ref,其余模块位于 hydraulic。以下必填数组应以相同顺序描述同一组真实回路;计数为整数、长度为米、局部阻力系数无量纲、流量比例为 0–1。管线内径必须为正,长度、粗糙度与 localK 非负。可选系统编号和附件路径用于压降诊断,不会把热模型变成逐系统/逐回路精细仿真。无显式路径时附件损失采用近似。不要用任意计数虚构此结构。
text
// Optional: ref.circuitryPD (DX) or hydraulic.circuitryPD (water/steam/dry cooler)
{
tubesPerCircuit: number[], returnBendsPerCircuit: number[],
crossoversPerCircuit: number[], circuitLengths_m: number[],
maxTubesPerCircuit: number, maxReturnBends: number, isUnbalanced: boolean,
systemCount?: number, circuitSystemIds?: string[], feederLengths_m?: number[],
localKPerCircuit?: number[], lengthImbalance_pct?: number,
hydraulicPaths?: Array<{
circuitId: number, systemId: string, systemFlowFraction: number,
circuitFlowFraction: number, tubeLength_m: number, connectorLength_m: number,
inletCommon: Line, inletBranch: Line, outletBranch: Line, outletCommon: Line
}>
}
// Line = { length_m: number, innerDiameter_m: number, roughness_m: number, localK: number }3. DX 蒸发器:固定流量性能计算
POST /api/v1/calculate/dx-evaporator 直接接收输入对象。ref 含 fluid、Tevap_C、superheat_K、circuits、mode;RATING 还需正值 mdot_ref_kg_s。x_in 是入口干度(默认 0.2);引擎要求 0 ≤ x_in < 1,虽然共享 schema 允许 1。Tevap_C 是吸气连接处的饱和温度;压力耦合可能使管入口饱和温度更高。fluid 必须准确匹配支持的属性表键名。
RATING 保留指定质量流量:出口干度和 achievedSuperheat_K 是结果,superheat_K 是目标。SIZING 需要 Q_target_W,根据目标负荷和设计焓升计算质量流量,再评估同一几何,不会自动扩大盘管。可选 fouling.R_ext/R_int 为非负 m²·K/W 热阻;引擎读取它们,但蒸发器共享 Zod schema 未列出。读取 outlet、perf、zones、htc、geometry 和 flags,重点检查 targetMet、hydraulicFeasible、pressureDropExcessive、notes,不能只看能量平衡。结霜和接近干涸的物理过程未解析。
json
{
"request": {
"air": {
"Vdot_m3_s": 1.5,
"T_in_C": 27,
"RH_in": 0.5,
"P_Pa": 101325
},
"coil": {
"height_m": 0.508,
"tubesPerRow": 20,
"width_m": 1,
"rows": 4,
"fpi": 12,
"Pt_m": 0.0254,
"Pl_m": 0.022,
"Do_m": 0.00952,
"wall_m": 0.0003,
"fin_m": 0.0001,
"tube_k": 386,
"fin_k": 200,
"freeAreaRatio": 0.6,
"finType": "plain"
},
"ref": {
"fluid": "R410A",
"Tevap_C": 5,
"superheat_K": 5,
"circuits": 10,
"mode": "RATING",
"mdot_ref_kg_s": 0.04,
"x_in": 0.2
},
"calib": {
"C_air": 1,
"C_tp": 1,
"C_sh": 1,
"f_maldistribution": 1
},
"segments": 40
},
"response": {
"success": true,
"data": {
"outlet": {
"T_out_C": 23.49883696449892,
"RH_out": 0.5951224553222765,
"W_out": 0.01076357974635124,
"h_out": 51029.9957183522,
"Tdp_out_C": 15.165690704059124
},
"perf": {
"Q_total_W": 7909.303263873674,
"Q_sens_W": 6229.595529054708,
"Q_lat_W": 1679.7077348189664,
"SHR": 0.7876288620147928,
"mcond_kg_s": 0.0006600788155553462,
"v_face_m_s": 2.952755905511811,
"dP_air_Pa": 83.01172194416893,
"dP_ref_Pa": 1516.4350589804817,
"Q_ref_W": 7909.303263873688,
"balanceError_pct": 1.4948764421579912e-13,
"mdot_ref_kg_s": 0.04,
"x_out": 1,
"achievedSuperheat_K": 21.745191335740323,
"targetSuperheat_K": 5,
"refrigerantOutlet": {
"T_C": 26.745191335740323,
"h_in_J_kg": 250687.86399999997,
"h_out_J_kg": 448420.44559684215,
"phase": "superheated"
},
"refrigerantPressure": {
"P_in_Pa": 937723.0350589807,
"P_out_Pa": 936206.6000000002,
"T_sat_in_C": 5.0521987063866804,
"T_sat_out_C": 5,
"satDrop_K": 0.05219870638668045,
"x_in_local": 0.19968718691574538,
"dP_twoPhase_Pa": 520.582915294799,
"dP_vapor_Pa": 995.8955933460854,
"dP_accessoriesInlet_Pa": 0,
"dP_accessoriesOutlet_Pa": 0,
"massFlux_kg_m2s": 64.00890550459303,
"hydraulicFeasible": true
}
},
"geometry": {
"A_face_m2": 0.508,
"A_ext_m2": 39.10246205044688,
"A_int_m2": 2.2418405176016765,
"n_tubes": 80,
"n_tubes_H": 20,
"L_circuit_m": 8,
"Di_m": 0.00892
},
"htc": {
"h_air_avg": 66.80366999738932,
"h_ref_avg": 507.4101139521869,
"U_overall": 15.758299149814324,
"eta_fin": 0.7703542918753953,
"eta_surface": 0.7837297035150003
},
"flags": {
"wetCoil": true,
"superheated": true,
"converged": true,
"oversized": true,
"targetMet": true,
"hydraulicFeasible": true,
"pressureDropExcessive": false,
"notes": [
"Refrigerant ΔP 1.5 kPa (G = 64 kg/m²s per circuit): saturation 5.05 °C at the tube inlets → 5.00 °C at the suction connection (drop 0.05 K, coupled into capacity).",
"Warning: Liquid velocity (0.06 m/s) is too low (<0.3 m/s). Risk of poor oil return and flow stratification.",
"Warning: Vapor velocity (1.78 m/s) is too low (<3 m/s). Risk of poor oil return.",
"Refrigerant-limited: achieved superheat 21.7 K exceeds target by more than 2 K (66 % of area superheating vapour). A TXV would increase mass flow and capacity.",
"Wet surface on 34 % of the coil area: SHR = 0.788, condensate 2.38 kg/h",
"Model: mean-circuit crossflow moving boundary with pressure-coupled saturation (MSH friction, Domanski–Hermes bends, homogeneous momentum); Chen two-phase HTC does not model dryout near x → 1."
]
},
"zones": {
"tp_fraction": 0.34306774086665626,
"sh_fraction": 0.6569322591333437,
"wet_fraction": 0.34306774086665626,
"Q_tp_W": 6885.446862985299,
"Q_sh_W": 1023.8564008883747
},
"timestamp": "2026-11-02T15:44:41.927Z",
"engineVersion": "6.1.0"
}
}
}4. DX 冷凝器:目标是排热量
POST /api/v1/calculate/dx-condenser 使用 ref.fluid、Tcond_C、Tin_gas_C、subcool_K、circuits、mode,以及 RATING 的 mdot_ref_kg_s。Tin_gas_C 是 °C 入口气体温度,不是排气过热度。要求 Tin_gas_C ≥ Tcond_C、subcool_K ≥ 0,Tcond_C 在该属性表的亚临界范围内。SIZING 中 Q_target_W 是冷凝器排热量,应包括上游计算的压缩机热量;流量由目标焓降推导,不会搜索更低的虚假负荷。
calib 含 C_air、C_dsh、C_cond、C_sc、f_maldistribution;可选 fouling 含 R_ext/R_int,单位 m²·K/W。结果使用 airOut、perf.Q_dsh_W/Q_cond_W/Q_sc_W、achievedSubcool_K、status、refrigerantOutlet.phase。zones 表示回路面积/长度比例,热量比例另见 heat_fractions。检查 capacityShortfall_pct、targetMet、pressureDropExcessive。热计算保持 Tcond 恒定,估计压降不会反馈到沿程饱和温度;不解析温度滑移及详细排间/回路相互作用。
json
{
"request": {
"air": {
"Vdot_m3_s": 1.5,
"T_in_C": 30,
"RH_in": 0.5,
"P_Pa": 101325
},
"coil": {
"height_m": 0.508,
"tubesPerRow": 20,
"width_m": 1,
"rows": 4,
"fpi": 12,
"Pt_m": 0.0254,
"Pl_m": 0.022,
"Do_m": 0.00952,
"wall_m": 0.0003,
"fin_m": 0.0001,
"tube_k": 386,
"fin_k": 200,
"freeAreaRatio": 0.6,
"finType": "plain"
},
"ref": {
"fluid": "R410A",
"Tcond_C": 45,
"subcool_K": 5,
"Tin_gas_C": 75,
"circuits": 10,
"mode": "RATING",
"mdot_ref_kg_s": 0.04
},
"calib": {
"C_air": 1,
"C_dsh": 1,
"C_cond": 1,
"C_sc": 1,
"f_maldistribution": 1
},
"fouling": {
"R_ext": 0,
"R_int": 0
},
"segments": 40
},
"response": {
"success": true,
"data": {
"engineVersion": "dx-cond-6.1.0",
"airOut": {
"T_out_C": 34.905833102639996,
"RH_out": 0.37920635932683405,
"W_out": 0.01331020383863019,
"h_out_J_kgda": 69268.25088365117
},
"perf": {
"Q_total_W": 8646.863272072569,
"Q_dsh_W": 1798.625303999998,
"Q_cond_W": 5929.402399999996,
"Q_sc_W": 918.8355680725742,
"v_face_m_s": 2.952755905511811,
"dP_air_Pa": 82.1050884443191,
"dP_ref_Pa": 265.3632161326799,
"mdot_ref_kg_s": 0.04,
"achievedSubcool_K": 12.142056810891162,
"status": "OK",
"satDrop_K": 0.004153328462578543,
"propertyModel": "coolprop_grid",
"Q_ref_W": 8646.863272072569,
"balanceError_pct": 1.8932766850595476e-13,
"requiredHeatRejection_W": 8124.959035999998,
"capacityShortfall_pct": 0,
"refrigerantOutlet": {
"T_C": 32.85794318910884,
"h_in_J_kg": 469048.89259999996,
"h_out_J_kg": 252877.31079818573,
"quality": null,
"phase": "subcooled"
},
"pressureDropBreakdown": {
"vapor_Pa": 103.73388610449132,
"liquid_Pa": 24.3684210978554,
"condensationFriction_Pa": 158.1821536620547,
"condensationBends_Pa": 8.76982049279011,
"acceleration_Pa": -29.691065224511664,
"accessories_Pa": 0
}
},
"zones": {
"dsh_fraction": 0.18317599713921148,
"cond_fraction": 0.5251466837984806,
"sc_fraction": 0.29167731906230787,
"heat_fractions": {
"dsh": 0.20800899093769123,
"cond": 0.6857287103348375,
"sc": 0.10626229872747119
}
},
"htc": {
"h_air_W_m2K": 66.77541103267734,
"h_ref_avg_W_m2K": 600.8301332918751,
"U_avg_W_m2K": 18.87836136527455,
"U_fouled_W_m2K": 18.87836136527455,
"eta_fin": 0.7704249008937955,
"eta_surface": 0.7837962000041732,
"h_dsh_W_m2K": 237.6991690054887,
"h_cond_W_m2K": 904.9932282548654,
"h_sc_W_m2K": 281.2531278597104
},
"geometry": {
"A_face_m2": 0.508,
"A_ext_m2": 39.10246205044688,
"A_int_m2": 2.2418405176016765,
"totalTubes": 80,
"tubesH": 20,
"L_circuit_m": 8,
"Di_m": 0.00892
},
"flags": {
"converged": true,
"oversized": false,
"targetMet": true,
"pressureDropExcessive": false,
"notes": [
"Mean-circuit pure-crossflow moving-boundary model: uniform air and refrigerant flow; not a row-by-row circuit simulation.",
"Single-phase enthalpies from the CoolProp superheated/subcooled property grid (piecewise cp = Δh/ΔT); temperature glide and saturation-pressure variation along the circuit are not resolved.",
"Target duty is condenser heat rejection, not evaporator cooling capacity; compressor power must be included upstream.",
"Multiple depth rows use a mean-crossflow approximation; row mixing and circuit/airflow interaction require independent validation.",
"Refrigerant ΔP uses mean-circuit area lengths, MSH friction, homogeneous acceleration and distributed bend estimates; gravity and pressure/thermal coupling are not resolved.",
"Warning: Liquid velocity (0.07 m/s) is too low (<0.3 m/s). Risk of poor oil return and flow stratification.",
"Warning: Vapor velocity (0.53 m/s) is too low (<3 m/s). Risk of poor oil return."
]
}
}
}
}5. 冷水盘管:必须提供质量流量
POST /api/v1/calculate/chilled-water 要求 water.flowType(mass 或 volumetric)、mdot_kg_s、T_in_C、glycol_pct。Vdot_m3_s 在此契约中只是可选信息;引擎直接使用 mdot_kg_s,不会换算仅含体积流量的请求。glycol_pct 为 0–60 的乙二醇质量百分比,0 表示水。冷水入口必须低于空气入口温度。该路由没有 water.T_out_C 目标或 mode 字段。
hydraulic 含 circuits、passes,可选 tubeCountOverride/circuitryPD。calib 含 C_air、C_w、f_fouling、f_maldistribution、approach_K。approach_K 仅为兼容保留并被忽略,可填 0,不能用作出口温度约束。passes 不会再次乘入回路长度。引擎把总污垢和分配不均因子限制为 0.5–1。结果包含 airOutlet、waterOutlet、显热/潜热、凝水 kg/s、SHR、wetAreaFraction、rowProfile。dP_water_kPa 为 kPa,dP_air_Pa 为 Pa。检查 regime、notes、收敛以及湿空气/流速警告。
json
{
"request": {
"air": {
"Vdot_m3_s": 1.5,
"T_in_C": 27,
"RH_in": 0.5,
"P_Pa": 101325
},
"water": {
"flowType": "mass",
"mdot_kg_s": 0.8,
"T_in_C": 7,
"glycol_pct": 0
},
"coil": {
"height_m": 0.508,
"width_m": 1,
"rows": 4,
"fpi": 12,
"Pt_m": 0.0254,
"Pl_m": 0.022,
"Do_m": 0.00952,
"wall_m": 0.0003,
"fin_m": 0.0001,
"tube_k": 386,
"fin_k": 200,
"freeAreaRatio": 0.6,
"finType": "plain",
"tubeMat": "Cu",
"finMat": "Al"
},
"hydraulic": {
"circuits": 10,
"passes": 1,
"tubeCountOverride": 20
},
"calib": {
"C_air": 1,
"C_w": 1,
"f_fouling": 1,
"f_maldistribution": 1,
"approach_K": 0
},
"segments": 40
},
"response": {
"success": true,
"data": {
"airOutlet": {
"T_out_C": 17.59280443908688,
"RH_out": 0.7765505714650607,
"W_out": 0.009740516735050291,
"h_out": 42378.12881134521,
"Tdp_out_C": 13.647149565122389
},
"waterOutlet": {
"T_out_C": 13.83298923251135,
"dT_K": 6.83298923251135
},
"perf": {
"Q_total_W": 22902.7552948312,
"Q_sens_W": 16738.15895260657,
"Q_lat_W": 6164.596342224632,
"SHR": 0.7308360385959376,
"mcond_kg_s": 0.0024330194247277745,
"v_face_m_s": 2.952755905511811,
"v_water_m_s": 1.2806100545209298,
"dP_air_Pa": 102.16101340852097,
"dP_water_kPa": 31.131087580896573,
"balanceError_pct": 1.588445914152848e-14
},
"geometry": {
"A_face_m2": 0.508,
"A_ext_m2": 39.10246205044688,
"A_int_m2": 2.2418405176016765,
"n_tubes": 80,
"n_tubes_H": 20,
"L_circuit_m": 8,
"Di_m": 0.00892
},
"htc": {
"h_air_avg": 66.82202962012009,
"h_water_avg": 5727.92773098421,
"U_overall": 45.13852142146351,
"eta_fin": 0.7703084264602427,
"eta_surface": 0.7836865094705112
},
"flags": {
"wetCoil": true,
"converged": true,
"oversized": false,
"regime": "Turbulent",
"notes": [
"Air ΔP includes a +30 % condensate allowance on the wet area (75 % wet); dry value 83 Pa.",
"Wet coil: 75 % of the area condensing, SHR = 0.731, latent 6.16 kW",
"Condensate rate: 8.76 kg/h"
],
"wetAreaFraction": 0.75,
"topology": "counter-cross-flow",
"rowProfile": [
{
"row": 1,
"Q_W": 5499.31813897424,
"T_air_out_C": 23.90926813806179,
"W_air_out": 0.011144473622459834,
"T_w_mean_C": 13.026969682536295,
"wetFraction": 0
},
{
"row": 2,
"Q_W": 5494.681101553189,
"T_air_out_C": 21.71020036768415,
"W_air_out": 0.010785290417758279,
"T_w_mean_C": 11.3995916157579,
"wetFraction": 1
},
{
"row": 3,
"Q_W": 5820.603392148445,
"T_air_out_C": 19.617081166279927,
"W_air_out": 0.010308018617014768,
"T_w_mean_C": 9.711871818476336,
"wetFraction": 1
},
{
"row": 4,
"Q_W": 6088.1526621553285,
"T_air_out_C": 17.59280443908688,
"W_air_out": 0.009740516735050291,
"T_w_mean_C": 7.936579335221592,
"wetFraction": 1
}
]
},
"timestamp": "2026-11-02T15:44:41.973Z",
"engineVersion": "6.0.0"
}
}
}6. 热水盘管:显热加热
POST /api/v1/calculate/hot-water 与冷水使用相同的 water、coil、hydraulic、calib 字段,但要求 water.T_in_C > air.T_in_C。即使 flowType 为 volumetric,也必须给出正值 mdot_kg_s。glycol_pct 指乙二醇质量百分比;该路由没有选择丙二醇的 fluidType。
引擎按给定几何和流量计算,不控制水出口温度,也不自动选型扩大盘管。approach_K 被忽略,passes 不会重复增加长度。加热时空气含湿量 W_out 保持不变,相对湿度随温度变化。结果含 airOutlet、waterOutlet、perf.Q_total_W、dP_water_kPa 和逐排诊断,没有通用 sensibleCapacity_kW 或 coilCode 字段。选型前检查 regime、流速警告和 flags.converged。
json
{
"request": {
"air": {
"Vdot_m3_s": 1.5,
"T_in_C": 15,
"RH_in": 0.5,
"P_Pa": 101325
},
"water": {
"flowType": "mass",
"mdot_kg_s": 0.8,
"T_in_C": 70,
"glycol_pct": 0
},
"coil": {
"height_m": 0.508,
"width_m": 1,
"rows": 4,
"fpi": 12,
"Pt_m": 0.0254,
"Pl_m": 0.022,
"Do_m": 0.00952,
"wall_m": 0.0003,
"fin_m": 0.0001,
"tube_k": 386,
"fin_k": 200,
"freeAreaRatio": 0.6,
"finType": "plain",
"tubeMat": "Cu",
"finMat": "Al"
},
"hydraulic": {
"circuits": 10,
"passes": 1,
"tubeCountOverride": 20
},
"calib": {
"C_air": 1,
"C_w": 1,
"f_fouling": 1,
"f_maldistribution": 1,
"approach_K": 0
},
"segments": 40
},
"response": {
"success": true,
"data": {
"airOutlet": {
"T_out_C": 45.761722198035464,
"RH_out": 0.08548275287573397,
"W_out": 0.0052785443390815584,
"h_out": 59687.224743425075
},
"waterOutlet": {
"T_out_C": 52.970971133489016,
"dT_K": 17.029028866510984
},
"perf": {
"Q_total_W": 56935.16608498108,
"v_face_m_s": 2.952755905511811,
"v_water_m_s": 1.3104547892703775,
"dP_air_Pa": 82.60160250830555,
"dP_water_kPa": 26.25240208261644,
"balanceError_pct": 2.5558747306799374e-14
},
"geometry": {
"A_face_m2": 0.508,
"A_ext_m2": 39.10246205044688,
"A_int_m2": 2.2418405176016765,
"n_tubes": 80,
"n_tubes_H": 20,
"L_circuit_m": 8,
"Di_m": 0.00892
},
"htc": {
"h_air_avg": 66.7732116534083,
"h_water_avg": 9792.613943179225,
"U_overall": 47.844060775088444,
"eta_fin": 0.7704303970347292,
"eta_surface": 0.7838013760296212
},
"flags": {
"converged": true,
"oversized": false,
"regime": "Turbulent",
"notes": [],
"topology": "counter-cross-flow",
"rowProfile": [
{
"row": 1,
"Q_W": 16668.64454630135,
"T_air_out_C": 24.00596675498907,
"T_w_mean_C": 55.41380080380971
},
{
"row": 2,
"Q_W": 14933.338963764221,
"T_air_out_C": 32.07435851144329,
"T_w_mean_C": 60.1476061140732
},
{
"row": 3,
"Q_W": 13369.768306539849,
"T_air_out_C": 39.297962599714644,
"T_w_mean_C": 64.38509129379582
},
{
"row": 4,
"Q_W": 11963.414268375656,
"T_air_out_C": 45.761722198035464,
"T_w_mean_C": 68.17579603667396
}
]
},
"timestamp": "2026-11-02T15:44:41.983Z",
"engineVersion": "6.0.0"
}
}
}7. 蒸汽盘管:表压与排凝限制
POST /api/v1/calculate/steam-coil 使用 steam.P_steam_kPa,单位 kPa 表压,参照 air.P_Pa 的当地大气压。属性表要求入口绝压 >20 且 ≤2000 kPa,饱和温度必须比入口空气高出超过 1 °C。steam.controlType 为 modulating/on_off,不代表动态控制仿真。明确提供 mode RATING 或 SIZING,REST 不应用 schema 默认值。subcooling_K 可选(引擎默认 5 K)。没有 quality 输入,假定入口是干饱和蒸汽。
calib 含 C_air、C_steam、f_fouling、f_noncondensables。SIZING 需正值 steam.Q_target_W,尝试 1–4 排,返回满足负荷的最小可行排数;若均不满足,返回四排结果并设 targetMet false。检查 selectedRows、pressureDropLimited、notes、steamOutlet、dP_steam_kPa。steamTrapCapacity_kg_h 和 dP_steamAssemblies_kPa 仅为初步参考,不是疏水阀/排凝认证。凝水过冷区域不单独建模;重力排凝、水锤、疏水阀可用压差及机械承压需独立工程核查。
json
{
"request": {
"air": {
"Vdot_m3_s": 1.5,
"T_in_C": 15,
"RH_in": 0.5,
"P_Pa": 101325
},
"steam": {
"P_steam_kPa": 100,
"controlType": "modulating",
"subcooling_K": 5,
"mode": "RATING"
},
"coil": {
"height_m": 0.508,
"width_m": 1,
"rows": 1,
"fpi": 8,
"Pt_m": 0.0254,
"Pl_m": 0.022,
"Do_m": 0.01588,
"wall_m": 0.0008,
"fin_m": 0.0001,
"tube_k": 386,
"fin_k": 200,
"freeAreaRatio": 0.65,
"finType": "plain",
"tubeMat": "Cu",
"finMat": "Al"
},
"hydraulic": {
"circuits": 20,
"passes": 1,
"tubeCountOverride": 20
},
"calib": {
"C_air": 1,
"C_steam": 1,
"f_fouling": 1,
"f_noncondensables": 1
},
"segments": 40
},
"response": {
"success": true,
"data": {
"airOutlet": {
"T_out_C": 34.079225932632134,
"RH_out": 0.15946330926782845,
"W_out": 0.0052785443390815584,
"h_out": 47819.933671807084
},
"steamOutlet": {
"T_sat_C": 120.4008265,
"T_condensate_C": 115.40022902366081,
"mdot_steam_kg_s": 0.015890787995762996,
"mdot_steam_kg_h": 57.206836784746784
},
"perf": {
"Q_total_W": 35312.68146348002,
"v_face_m_s": 2.952755905511811,
"dP_air_Pa": 79.84088218559907,
"dP_steamAssemblies_kPa": 0,
"steamTrapCapacity_kg_h": 143.01709196186695,
"dP_steam_kPa": 0.004148565054761704,
"v_steam_in_m_s": 4.3669848655833485,
"satTempDrop_K": 0.0005974763391805027,
"balanceError_pct": 2.0604375857744306e-14,
"effectiveness": 0.18101641744854888,
"NTU": 0.19969124105470984,
"UA_W_K": 369.59744652696935
},
"geometry": {
"A_face_m2": 0.508,
"A_ext_m2": 5.494324834912423,
"A_int_m2": 0.8972388618652448,
"n_tubes": 20,
"n_tubes_H": 20,
"L_circuit_m": 1,
"Di_m": 0.014279999999999998
},
"htc": {
"h_air_avg": 69.05378275896463,
"h_steam_avg": 16452.208245445134,
"U_overall": 67.26894707397848,
"eta_fin": 0.9040208158032803,
"eta_surface": 0.9208501857263931
},
"flags": {
"converged": true,
"oversized": false,
"notes": [
"In-tube condensation: max(Chato gravity-driven, Shah shear-driven) — governing: Chato (stratified); inlet vapour Re = 5474.",
"Steam ΔP in governing circuit 0.00 kPa → T_sat drop 0.00 K; capacity uses T_sat at the mean circuit pressure (120.4 °C).",
"Condensate hydrostatic head across the coil: 4.7 kPa (0 return bends per circuit). Ensure gravity drainage and trap differential.",
"Steam use includes 5.0 K condensate subcooling (h_fg + cp·ΔT_sub); the subcooling area is not modelled separately."
],
"pressureDropLimited": false,
"condensationModel": "Chato (stratified)",
"rowProfile": [
{
"row": 1,
"Q_W": 35312.68146348002,
"T_air_out_C": 34.079225932632134,
"h_steam_W_m2K": 16452.208245445134
}
]
},
"timestamp": "2026-11-02T15:44:41.989Z",
"engineVersion": "5.0.0"
}
}
}8. 干冷器:REST 仅执行单盘管性能计算
POST /api/v1/calculate/dry-cooler 的 air 不同:T_db_C、RH、altitude_m,以及 Vdot_m3_s 或 v_face_m_s。同时提供时正值 v_face_m_s 优先。fluid 使用 fluidType water/eg/pg、glycolPct(质量百分比 0–60)、T_in_C、正值 mdot_kg_s 或 Vdot_m3_s;质量流量优先。流体入口必须比空气更热。calib 使用 C_air、C_fluid、f_fouling_air、f_fouling_fluid、可选 R_fouling_air_m2KW/R_fouling_fluid_m2KW(m²·K/W)、f_maldistribution、approach_K;approach_K 被忽略。
此 REST 路由只调用 solveDryCooler。共享类型虽列有 fluid.T_out_C、vShape、vAngle_deg,但这些字段不会在此启用目标出口温度求解或 V 形求解器。这里没有 /dry-cooler/balanced 路由。响应是单盘管结果,含 airOutlet、fluidOutlet、Q_total_W、LMTD_K、F_correction、effectiveness、NTU 和冻结诊断。此排热模型 Q_lat_W 为 0、wetCoil 为 false;不是喷淋绝热/蒸发冷却器。检查 nearFreezing、freezingMargin_K、regime、收敛和 notes。
json
{
"request": {
"air": {
"T_db_C": 30,
"RH": 0.5,
"altitude_m": 0,
"Vdot_m3_s": 1.5
},
"fluid": {
"fluidType": "eg",
"glycolPct": 30,
"T_in_C": 45,
"mdot_kg_s": 0.8
},
"coil": {
"height_m": 0.508,
"width_m": 1,
"rows": 4,
"fpi": 10,
"Pt_m": 0.0254,
"Pl_m": 0.022,
"Do_m": 0.01588,
"wall_m": 0.0005,
"fin_m": 0.0002,
"tube_k": 386,
"fin_k": 200,
"freeAreaRatio": 0.55,
"finType": "plain",
"tubeMat": "Cu",
"finMat": "Al"
},
"hydraulic": {
"circuits": 10,
"passes": 1,
"tubeCountOverride": 20
},
"calib": {
"C_air": 1,
"C_fluid": 1,
"f_fouling_air": 1,
"f_fouling_fluid": 1,
"R_fouling_air_m2KW": 0,
"R_fouling_fluid_m2KW": 0,
"f_maldistribution": 1,
"approach_K": 0
},
"segments": 40
},
"response": {
"success": true,
"data": {
"airOutlet": {
"T_out_C": 37.963588732151216,
"RH_out": 0.32077369527978405,
"W_out": 0.01331020383863019,
"h_out": 72420.05383927401
},
"fluidOutlet": {
"T_out_C": 40.1532216213745,
"dT_K": 4.846778378625501
},
"perf": {
"Q_total_W": 14036.364768477986,
"Q_sens_W": 14036.364768477986,
"Q_lat_W": 0,
"v_face_m_s": 2.952755905511811,
"v_fluid_m_s": 0.44169081528152904,
"dP_air_Pa": 220.66091438182707,
"dP_fluid_kPa": 3.170390159951273,
"balanceError_pct": 2.2030504600253869e-13,
"LMTD_K": 8.499786553833324,
"F_correction": 0.9964684620436388,
"effectiveness": 0.530905915476746,
"NTU": 0.9402368011687094
},
"geometry": {
"A_face_m2": 0.508,
"A_ext_m2": 26.353776660889263,
"A_int_m2": 3.7397518948332893,
"n_tubes": 80,
"n_tubes_H": 20,
"L_circuit_m": 8,
"Di_m": 0.014879999999999997
},
"htc": {
"h_air_avg": 158.41035024054196,
"h_fluid_avg": 784.605812708763,
"U_overall": 62.88400693514512,
"UA_W_K": 1657.2310743106261,
"eta_fin": 0.8992749036562225,
"eta_surface": 0.9133028338448336
},
"flags": {
"wetCoil": false,
"wetFraction": 0,
"converged": true,
"oversized": false,
"regime": "Transitional",
"nearFreezing": false,
"freezingPoint_C": -13.544999999999998,
"freezingMargin_K": 53.6982216213745,
"notes": [
"Warning: Glycol mixture velocity (0.44 m/s) below 0.5 m/s. Glycol mixtures need higher velocity for adequate heat transfer.",
"Notice: Fluid flow is transitional (Re = 2798). Results may have higher uncertainty.",
"Dry cooler: the fin surface is warmer than the air, so no condensation can occur (latent capacity = 0)."
],
"topology": "counter-cross-flow",
"rowProfile": [
{
"row": 1,
"Q_W": 3885.8246219918224,
"T_air_out_C": 32.20463842919675,
"T_w_mean_C": 40.80778501827438
},
{
"row": 2,
"Q_W": 3634.220318092688,
"T_air_out_C": 34.266528131601234,
"T_w_mean_C": 42.10730054946271
},
{
"row": 3,
"Q_W": 3382.1877594860885,
"T_air_out_C": 36.18542613516059,
"T_w_mean_C": 43.31977794477613
},
{
"row": 4,
"Q_W": 3134.1320689073873,
"T_air_out_C": 37.963588732151216,
"T_w_mean_C": 44.445822404284186
}
]
},
"timestamp": "2026-11-02T15:44:42.006Z",
"engineVersion": "2.0.0"
}
}
}9. 两条 balanced 路由并不相同
POST /api/v1/calculate/dx-evaporator/balanced 要求 {inputs: <完整蒸发器输入>, options?: {tolPct?, maxIt?}}。它搜索达到目标出口过热度的制冷剂质量流量,即膨胀阀工作点;能力是结果,不只是让空气/制冷剂热量相等。内部改用 RATING,缺省流量时使用正初值。maxIt 默认 60。原始输入为 SIZING 时,tolPct(默认 1)检查能力缺口,而不是过热度求解误差;引擎过热度接受误差为 0.05 K。即使返回结果,targetMet/converged 也可能为 false,不会调整校准。
POST /api/v1/calculate/dx-condenser/balanced 直接接收冷凝器输入,不接受 {inputs, options} 包装。它调用普通冷凝器引擎,保留 RATING 流量,设 iterations 为 1,并在 SIZING 下检查负荷、液态出口和过冷度。REST 不传第三个 options 参数,因此发送 options 不会开放内部流量边界、maxIt 或容差。不能描述为搜索更低冷凝器流量来掩盖能力不足。两者都使用各自普通模块的结果结构。
json
[
{
"method": "POST",
"path": "/api/v1/calculate/dx-evaporator/balanced",
"request": {
"inputs": {
"air": {
"Vdot_m3_s": 1.5,
"T_in_C": 27,
"RH_in": 0.5,
"P_Pa": 101325
},
"coil": {
"height_m": 0.508,
"tubesPerRow": 20,
"width_m": 1,
"rows": 4,
"fpi": 12,
"Pt_m": 0.0254,
"Pl_m": 0.022,
"Do_m": 0.00952,
"wall_m": 0.0003,
"fin_m": 0.0001,
"tube_k": 386,
"fin_k": 200,
"freeAreaRatio": 0.6,
"finType": "plain"
},
"ref": {
"fluid": "R410A",
"Tevap_C": 5,
"superheat_K": 5,
"circuits": 10,
"mode": "RATING",
"mdot_ref_kg_s": 0.04,
"x_in": 0.2
},
"calib": {
"C_air": 1,
"C_tp": 1,
"C_sh": 1,
"f_maldistribution": 1
},
"segments": 40
},
"options": {
"tolPct": 1,
"maxIt": 60
}
},
"response": {
"success": true,
"data": {
"outlet": {
"T_out_C": 16.37866583468195,
"RH_out": 0.7700295163271693,
"W_out": 0.008931554267298955,
"h_out": 39086.848765679584,
"Tdp_out_C": 12.341546239274933
},
"perf": {
"Q_total_W": 28606.45485650264,
"Q_sens_W": 18898.46749721315,
"Q_lat_W": 9707.987359289491,
"SHR": 0.660636474949893,
"mcond_kg_s": 0.0038349295656768378,
"v_face_m_s": 2.952755905511811,
"dP_air_Pa": 83.4970954841905,
"dP_ref_Pa": 18853.52619300515,
"Q_ref_W": 28606.45485650279,
"balanceError_pct": 5.214107509615256e-13,
"mdot_ref_kg_s": 0.1606828269347608,
"x_out": 1,
"achievedSuperheat_K": 5.013566038697411,
"targetSuperheat_K": 5,
"refrigerantOutlet": {
"T_C": 10.01356603869741,
"h_in_J_kg": 250687.86399999997,
"h_out_J_kg": 428718.4314365398,
"phase": "superheated"
},
"refrigerantPressure": {
"P_in_Pa": 955060.1261930054,
"P_out_Pa": 936206.6000000002,
"T_sat_in_C": 5.648975814871859,
"T_sat_out_C": 5,
"satDrop_K": 0.648975814871859,
"x_in_local": 0.19609440443287166,
"dP_twoPhase_Pa": 17333.776101730764,
"dP_vapor_Pa": 1524.1357220685973,
"dP_accessoriesInlet_Pa": 0,
"dP_accessoriesOutlet_Pa": 0,
"massFlux_kg_m2s": 257.12829713694947,
"hydraulicFeasible": true
}
},
"geometry": {
"A_face_m2": 0.508,
"A_ext_m2": 39.10246205044688,
"A_int_m2": 2.2418405176016765,
"n_tubes": 80,
"n_tubes_H": 20,
"L_circuit_m": 8,
"Di_m": 0.00892
},
"htc": {
"h_air_avg": 66.82588196002244,
"h_ref_avg": 3152.8354872556492,
"U_overall": 39.48790359750422,
"eta_fin": 0.7702988035387852,
"eta_surface": 0.7836774470234328
},
"flags": {
"wetCoil": true,
"superheated": true,
"converged": true,
"oversized": false,
"targetMet": true,
"hydraulicFeasible": true,
"pressureDropExcessive": false,
"notes": [
"Refrigerant ΔP 18.9 kPa (G = 257 kg/m²s per circuit): saturation 5.65 °C at the tube inlets → 5.00 °C at the suction connection (drop 0.65 K, coupled into capacity).",
"Warning: Liquid velocity (0.22 m/s) is too low (<0.3 m/s). Risk of poor oil return and flow stratification.",
"Wet surface on 93 % of the coil area: SHR = 0.661, condensate 13.81 kg/h",
"Model: mean-circuit crossflow moving boundary with pressure-coupled saturation (MSH friction, Domanski–Hermes bends, homogeneous momentum); Chen two-phase HTC does not model dryout near x → 1.",
"TXV: mdot_ref = 0.16068 kg/s gives 5.01 K superheat (12 evaluations)."
],
"iterations": 12
},
"zones": {
"tp_fraction": 0.9259358677567262,
"sh_fraction": 0.0740641322432738,
"wet_fraction": 0.9259358677567262,
"Q_tp_W": 27660.548469301222,
"Q_sh_W": 945.9063872014204
},
"timestamp": "2026-11-02T15:44:42.158Z",
"engineVersion": "6.1.0"
}
}
},
{
"method": "POST",
"path": "/api/v1/calculate/dx-condenser/balanced",
"request": {
"air": {
"Vdot_m3_s": 1.5,
"T_in_C": 30,
"RH_in": 0.5,
"P_Pa": 101325
},
"coil": {
"height_m": 0.508,
"tubesPerRow": 20,
"width_m": 1,
"rows": 4,
"fpi": 12,
"Pt_m": 0.0254,
"Pl_m": 0.022,
"Do_m": 0.00952,
"wall_m": 0.0003,
"fin_m": 0.0001,
"tube_k": 386,
"fin_k": 200,
"freeAreaRatio": 0.6,
"finType": "plain"
},
"ref": {
"fluid": "R410A",
"Tcond_C": 45,
"subcool_K": 5,
"Tin_gas_C": 75,
"circuits": 10,
"mode": "RATING",
"mdot_ref_kg_s": 0.04
},
"calib": {
"C_air": 1,
"C_dsh": 1,
"C_cond": 1,
"C_sc": 1,
"f_maldistribution": 1
},
"fouling": {
"R_ext": 0,
"R_int": 0
},
"segments": 40
},
"response": {
"success": true,
"data": {
"engineVersion": "dx-cond-6.1.0",
"airOut": {
"T_out_C": 34.905833102639996,
"RH_out": 0.37920635932683405,
"W_out": 0.01331020383863019,
"h_out_J_kgda": 69268.25088365117
},
"perf": {
"Q_total_W": 8646.863272072569,
"Q_dsh_W": 1798.625303999998,
"Q_cond_W": 5929.402399999996,
"Q_sc_W": 918.8355680725742,
"v_face_m_s": 2.952755905511811,
"dP_air_Pa": 82.1050884443191,
"dP_ref_Pa": 265.3632161326799,
"mdot_ref_kg_s": 0.04,
"achievedSubcool_K": 12.142056810891162,
"status": "OK",
"satDrop_K": 0.004153328462578543,
"propertyModel": "coolprop_grid",
"Q_ref_W": 8646.863272072569,
"balanceError_pct": 1.8932766850595476e-13,
"requiredHeatRejection_W": 8124.959035999998,
"capacityShortfall_pct": 0,
"refrigerantOutlet": {
"T_C": 32.85794318910884,
"h_in_J_kg": 469048.89259999996,
"h_out_J_kg": 252877.31079818573,
"quality": null,
"phase": "subcooled"
},
"pressureDropBreakdown": {
"vapor_Pa": 103.73388610449132,
"liquid_Pa": 24.3684210978554,
"condensationFriction_Pa": 158.1821536620547,
"condensationBends_Pa": 8.76982049279011,
"acceleration_Pa": -29.691065224511664,
"accessories_Pa": 0
}
},
"zones": {
"dsh_fraction": 0.18317599713921148,
"cond_fraction": 0.5251466837984806,
"sc_fraction": 0.29167731906230787,
"heat_fractions": {
"dsh": 0.20800899093769123,
"cond": 0.6857287103348375,
"sc": 0.10626229872747119
}
},
"htc": {
"h_air_W_m2K": 66.77541103267734,
"h_ref_avg_W_m2K": 600.8301332918751,
"U_avg_W_m2K": 18.87836136527455,
"U_fouled_W_m2K": 18.87836136527455,
"eta_fin": 0.7704249008937955,
"eta_surface": 0.7837962000041732,
"h_dsh_W_m2K": 237.6991690054887,
"h_cond_W_m2K": 904.9932282548654,
"h_sc_W_m2K": 281.2531278597104
},
"geometry": {
"A_face_m2": 0.508,
"A_ext_m2": 39.10246205044688,
"A_int_m2": 2.2418405176016765,
"totalTubes": 80,
"tubesH": 20,
"L_circuit_m": 8,
"Di_m": 0.00892
},
"flags": {
"converged": true,
"oversized": false,
"targetMet": true,
"pressureDropExcessive": false,
"notes": [
"Mean-circuit pure-crossflow moving-boundary model: uniform air and refrigerant flow; not a row-by-row circuit simulation.",
"Single-phase enthalpies from the CoolProp superheated/subcooled property grid (piecewise cp = Δh/ΔT); temperature glide and saturation-pressure variation along the circuit are not resolved.",
"Target duty is condenser heat rejection, not evaporator cooling capacity; compressor power must be included upstream.",
"Multiple depth rows use a mean-crossflow approximation; row mixing and circuit/airflow interaction require independent validation.",
"Refrigerant ΔP uses mean-circuit area lengths, MSH friction, homogeneous acceleration and distributed bend estimates; gravity and pressure/thermal coupling are not resolved.",
"Warning: Liquid velocity (0.07 m/s) is too low (<0.3 m/s). Risk of poor oil return and flow stratification.",
"Warning: Vapor velocity (0.53 m/s) is too low (<3 m/s). Risk of poor oil return."
],
"iterations": 1
}
}
}
}
]10. 成功响应与查询结果
计算成功返回 HTTP 200,格式 {success:true,data:<引擎结果>},没有统一能力改名、coilCode、分页或保存项目。能力为 W;制冷剂/凝水流量通常为 kg/s,明确 kg_h 的字段除外;空气/DX 压降为 Pa,液体/蒸汽以 kPa 结尾的字段为 kPa。示例给出完整合成响应。下面的紧凑字段表还列出条件字段;它是字段记法,不是可执行 TypeScript 或 JSON 请求。可选字段可能缺失。
HTTP 成功仅表示引擎返回,不证明满足负荷或可安全制造。检查 flags.converged、flags.notes、适用时的 targetMet、实际过热/过冷度、出口相态、水力及冻结诊断。很小的 balanceError_pct 只是内部守恒残差,不是独立实验室验证。冷凝器返回 engineVersion,但不含 timestamp;不要假设元数据完全一致。
GET /api/v1/refrigerants 仅返回 data 中的准确制冷剂名称数组,不含 GWP、ODP、安全等级或属性表。GET /api/v1/health 直接返回 status、version、ISO timestamp,不带 success/data;version 是 API 版本,不是各引擎版本。两条 GET 均需身份验证。列出某制冷剂不代表支持跨临界或无限温度范围。
text
// HTTP 200 calculators: { success: true, data: Result }
// A trailing ? marks an optional field; names and units are literal API keys.
Air = {T_out_C, RH_out, W_out, h_out}; // numbers: °C, fraction, kg/kg dry air, J/kg dry air
Geometry = {A_face_m2, A_ext_m2, A_int_m2, n_tubes, n_tubes_H, L_circuit_m, Di_m};
HTC = {h_air_avg, U_overall, eta_fin, eta_surface}; // W/(m²·K), efficiencies 0–1
Row = {row, Q_W, T_air_out_C, T_w_mean_C};
DXEvaporator = {
outlet: Air & {Tdp_out_C}, geometry: Geometry, htc: HTC & {h_ref_avg},
perf: {Q_total_W,Q_sens_W,Q_lat_W,SHR,mcond_kg_s,v_face_m_s,dP_air_Pa,dP_ref_Pa,
Q_ref_W,balanceError_pct,mdot_ref_kg_s,x_out,achievedSuperheat_K?,targetSuperheat_K?,
targetCapacity_W?,capacityShortfall_pct?,
refrigerantOutlet?: {T_C,h_in_J_kg,h_out_J_kg,phase},
refrigerantPressure?: {P_in_Pa,P_out_Pa,T_sat_in_C,T_sat_out_C,satDrop_K,x_in_local,
dP_twoPhase_Pa,dP_vapor_Pa,dP_accessoriesInlet_Pa,dP_accessoriesOutlet_Pa,massFlux_kg_m2s,hydraulicFeasible}},
zones?: {tp_fraction,sh_fraction,wet_fraction,Q_tp_W,Q_sh_W},
flags: {wetCoil,superheated,converged,oversized,targetMet?,hydraulicFeasible?,pressureDropExcessive?,iterations?,notes},
timestamp, engineVersion
};
DXCondenser = {
airOut: {T_out_C,RH_out,W_out,h_out_J_kgda},
perf: {Q_total_W,Q_dsh_W,Q_cond_W,Q_sc_W,v_face_m_s,dP_air_Pa,dP_ref_Pa?,
mdot_ref_kg_s,achievedSubcool_K,status,satDrop_K?,propertyModel?,Q_ref_W,balanceError_pct,
targetCapacity_W?,targetError_pct?,requiredHeatRejection_W?,capacityShortfall_pct?,
refrigerantOutlet?: {T_C,h_in_J_kg,h_out_J_kg,quality,phase},
pressureDropBreakdown?: {vapor_Pa,liquid_Pa,condensationFriction_Pa,condensationBends_Pa,acceleration_Pa,accessories_Pa}},
zones: {dsh_fraction,cond_fraction,sc_fraction,heat_fractions?:{dsh,cond,sc}},
htc: {h_air_W_m2K,h_ref_avg_W_m2K,U_avg_W_m2K,U_fouled_W_m2K?,eta_fin,eta_surface,h_dsh_W_m2K?,h_cond_W_m2K?,h_sc_W_m2K?},
geometry: {A_face_m2,A_ext_m2,A_int_m2,totalTubes,tubesH?,L_circuit_m?,Di_m?},
flags: {converged,iterations?,oversized,targetMet?,pressureDropExcessive?,notes}, engineVersion?
};
ChilledWater = {
airOutlet: Air & {Tdp_out_C}, waterOutlet:{T_out_C,dT_K}, geometry:Geometry,
htc:HTC & {h_water_avg},
perf:{Q_total_W,Q_sens_W,Q_lat_W,SHR,mcond_kg_s,v_face_m_s,v_water_m_s?,dP_air_Pa,dP_water_kPa,balanceError_pct},
flags:{wetCoil,converged,oversized,regime,notes,wetAreaFraction?,topology?,
rowProfile?: Array<Row & {W_air_out,wetFraction}>}, timestamp,engineVersion
};
HotWater = {
airOutlet:Air,waterOutlet:{T_out_C,dT_K},geometry:Geometry,htc:HTC & {h_water_avg},
perf:{Q_total_W,v_face_m_s,v_water_m_s?,dP_air_Pa,dP_water_kPa,balanceError_pct},
flags:{converged,oversized,regime,notes,topology?,rowProfile?:Row[]},timestamp,engineVersion
};
Steam = {
airOutlet:Air,steamOutlet:{T_sat_C,T_condensate_C,mdot_steam_kg_s,mdot_steam_kg_h},
geometry:Geometry,htc:HTC & {h_steam_avg},
perf:{Q_total_W,v_face_m_s,dP_air_Pa,dP_steamAssemblies_kPa,steamTrapCapacity_kg_h,
dP_steam_kPa?,v_steam_in_m_s?,satTempDrop_K?,balanceError_pct?,effectiveness?,NTU?,UA_W_K?},
flags:{converged,oversized,notes,targetMet?,selectedRows?,pressureDropLimited?,condensationModel?,
rowProfile?:Array<{row,Q_W,T_air_out_C,h_steam_W_m2K}>},timestamp,engineVersion
};
DryCooler = {
airOutlet:Air,fluidOutlet:{T_out_C,dT_K},geometry:Geometry,htc:HTC & {h_fluid_avg,UA_W_K},
perf:{Q_total_W,Q_sens_W,Q_lat_W,v_face_m_s,v_fluid_m_s,dP_air_Pa,dP_fluid_kPa,
balanceError_pct,LMTD_K,F_correction,effectiveness,NTU},
flags:{wetCoil,wetFraction,converged,oversized,regime,nearFreezing,freezingPoint_C,freezingMargin_K,
notes,topology?,rowProfile?:Row[],targetMet?},timestamp,engineVersion
};
// Numbers unless named otherwise: flags booleans; notes string[]; rowProfile arrays.
// timestamp: ISO string; engineVersion/regime/topology/propertyModel/status/phase/condensationModel: strings.
// Condenser refrigerantOutlet.quality: number | null. No condenser timestamp is returned.
// Evaporator phase: two_phase | saturated_vapor | superheated.
// Condenser phase: superheated | two_phase | saturated_liquid | subcooled.
// Condenser status type: OK | NO_CONDENSE | NO_SUBCOOL | LIMITED_UA | PARTIAL.
// Current condenser solver emits OK, NO_CONDENSE, NO_SUBCOOL or PARTIAL.
// propertyModel: coolprop_grid | constant_cp_fallback; topology: counter-cross-flow.
// condensationModel: Chato (stratified) | Shah (annular).
// GET /api/v1/health: {status:"ok",version:"1.0.0",timestamp:"<ISO>"}
// GET /api/v1/refrigerants: {success:true,data:["R32","R410A","R134a","R22","R290","R1234yf","R404A","R507A","R407C","R1234ze(E)","R717","R744","R600a","R1270","R123","R245fa"]}11. 错误、限流与安全排查
路由 JSON 错误格式为 {error:<代码>,message:<文本>},没有 success:false 或逐字段错误数组。以下为原始消息模板,尖括号内容可变。普通 DX 的缺少制冷剂和未知制冷剂消息不同;蒸发器 balanced 先检查 inputs,两条 balanced 均返回较短 Unknown refrigerant 消息。缺失嵌套字段也可能抛异常转为 422。对象检查很浅,JavaScript 数组也算对象,不能依赖它完成输入验证。
401 检查 Bearer、exk_ 格式和密钥有效性,勿泄露密钥。403 检查吊销、到期、订阅状态和 calc:read。400 修正格式或制冷剂键名。422 按引擎消息核对单位、必填项、流量/温度顺序、几何及属性范围,不要盲目重试。未捕获的认证/存储错误不由 wrapSolver 规范化。畸形 JSON 或超大请求可能在进入 REST 前被 Express 拒绝;应用 JSON parser 限额为 50mb,这类错误不保证上述 JSON 格式。
限流按密钥保存在进程内存,60 秒窗口从首次通过认证的请求开始。使用密钥配置值,值为假值时回退到每分钟 100 次;这不是统一套餐配额,也不是分布式限流。认证/限流通过后及 429 响应设置 X-RateLimit-Limit、X-RateLimit-Remaining、X-RateLimit-Reset(Unix 秒),并非每个 401/403 都有。认证后的权限/输入失败消耗限额。遇到 429 等待 reset 并采用有界退避,不保证 Retry-After。日志只记录路径、合成/脱敏输入、HTTP 状态和诊断,不记录秘密。
text
HTTP 401: {"error":"unauthorized","message":"Missing or invalid Authorization header. Use: Bearer exk_your_api_key"}
HTTP 401: {"error":"unauthorized","message":"Invalid API key format. Keys start with 'exk_'."}
HTTP 401: {"error":"unauthorized","message":"Invalid API key."}
HTTP 403: {"error":"forbidden","message":"API key has been revoked."}
HTTP 403: {"error":"forbidden","message":"API key has expired."}
HTTP 403: {"error":"forbidden","message":"API access requires an active Enterprise or Manufacturer subscription."}
HTTP 403: {"error":"forbidden","message":"This API key does not have the 'calc:read' permission."}
HTTP 429: {"error":"rate_limit_exceeded","message":"Rate limit of <limit> requests per minute exceeded. Try again later."}
HTTP 400: {"error":"bad_request","message":"Request body must be a JSON object with calculation inputs."}
HTTP 400: {"error":"bad_request","message":"Missing refrigerant in input. Provide ref.fluid (or legacy ref.refrigerant)."}
HTTP 400: {"error":"bad_request","message":"Unknown refrigerant '<name>'. Available: <keys>"}
HTTP 400: {"error":"bad_request","message":"Request body must contain 'inputs' and optional 'options' fields."}
HTTP 400: {"error":"bad_request","message":"Unknown refrigerant '<name>'."}
HTTP 422: {"error":"calculation_error","message":"<engine error>"}
// Non-Error fallbacks: normal routes = Calculation failed; balanced routes = Balanced solve failed.