Files
CapMachine/CapMachine.Wpf/PPCalculation/ThermodynamicSixResultsCalculator.cs

997 lines
34 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using CapMachine.Core;
using System;
using System.Diagnostics;
using System.Text;
namespace CapMachine.Wpf.PPCalculation
{
/// <summary>
/// 六个物性结果(制热量/COP(制热)/等熵效率/制冷量/COP(制冷)/容积效率)计算封装类。
///
/// 说明:
/// - 本类用于将原先位于 PPCService 的计算过程完整搬迁为独立类,方便后续维护与对比验证。
/// - 计算公式、单位换算、REFPROP 调用链路应与现有实现保持一致,仅做结构性封装。
/// </summary>
public sealed class ThermodynamicSixResultsCalculator
{
private readonly object _refpropLock;
private static volatile bool _rpInitialized;
private static string _rpFluidFile = string.Empty;
private double _h3TempOffset_C = -10.0;
public void SetH3TempOffset_C(double offsetC)
{
if (double.IsNaN(offsetC) || double.IsInfinity(offsetC))
{
return;
}
_h3TempOffset_C = offsetC;
}
/// <summary>
/// 构造函数。
/// </summary>
/// <param name="refpropLock">REFPROP 全局互斥锁对象(建议传入与 PPCService 相同的锁对象,避免并发竞态)。</param>
public ThermodynamicSixResultsCalculator(object refpropLock)
{
_refpropLock = refpropLock ?? throw new ArgumentNullException(nameof(refpropLock));
}
/// <summary>
/// 输入模型(从 Tag 或外部来源读取后传入)。
/// </summary>
public readonly struct Input
{
public Input(
double suctionPress_BarA,
double suctionTemp_C,
double dischargePress_BarA,
double dischargeTemp_C,
double txvFrPress_BarA,
double txvFrTemp_C,
double hvPower_W,
double totalFlow_kg_h,
double speed_rpm,
double displacement_cc)
{
SuctionPress_BarA = suctionPress_BarA;
SuctionTemp_C = suctionTemp_C;
DischargePress_BarA = dischargePress_BarA;
DischargeTemp_C = dischargeTemp_C;
TxvFrPress_BarA = txvFrPress_BarA;
TxvFrTemp_C = txvFrTemp_C;
HvPower_W = hvPower_W;
TotalFlow_kg_h = totalFlow_kg_h;
Speed_rpm = speed_rpm;
Displacement_cc = displacement_cc;
}
public double SuctionPress_BarA { get; }
public double SuctionTemp_C { get; }
public double DischargePress_BarA { get; }
public double DischargeTemp_C { get; }
public double TxvFrPress_BarA { get; }
public double TxvFrTemp_C { get; }
public double HvPower_W { get; }
public double TotalFlow_kg_h { get; }
public double Speed_rpm { get; }
public double Displacement_cc { get; }
}
/// <summary>
/// 计算输出模型。
/// </summary>
public readonly struct Result
{
public Result(
double heatingCapacityQh_kW,
double coolingCapacityQc_kW,
double copHeating,
double copCooling,
double isentropicEfficiencyPct,
double volumetricEfficiencyPct,
double mRef_kg_s,
double w_kW,
double h1_kJkg,
double s1_JmolK,
double v1_m3kg,
double h2_kJkg,
double h3_kJkg,
double h2s_kJkg)
{
HeatingCapacityQh_kW = heatingCapacityQh_kW;
CoolingCapacityQc_kW = coolingCapacityQc_kW;
COPHeating = copHeating;
COPCooling = copCooling;
IsentropicEfficiencyPct = isentropicEfficiencyPct;
VolumetricEfficiencyPct = volumetricEfficiencyPct;
MRef_kg_s = mRef_kg_s;
W_kW = w_kW;
H1_kJkg = h1_kJkg;
S1_JmolK = s1_JmolK;
V1_m3kg = v1_m3kg;
H2_kJkg = h2_kJkg;
H3_kJkg = h3_kJkg;
H2s_kJkg = h2s_kJkg;
}
public double HeatingCapacityQh_kW { get; }
public double CoolingCapacityQc_kW { get; }
public double COPHeating { get; }
public double COPCooling { get; }
public double IsentropicEfficiencyPct { get; }
public double VolumetricEfficiencyPct { get; }
public double MRef_kg_s { get; }
public double W_kW { get; }
public double H1_kJkg { get; }
public double S1_JmolK { get; }
public double V1_m3kg { get; }
public double H2_kJkg { get; }
public double H3_kJkg { get; }
public double H2s_kJkg { get; }
}
/// <summary>
/// 计算六个物性结果。
///
/// 返回值:
/// - true至少已成功计算 Qh/Qc/COP/ηs容积效率若失败将返回 NaN但本方法仍返回 true并通过 error 输出警告信息。
/// - false关键输入/REFPROP 计算失败。
/// </summary>
/// <param name="input">输入参数。</param>
/// <param name="result">输出结果。</param>
/// <param name="error">错误/警告信息。</param>
/// <returns>是否成功。</returns>
public bool TryCalculate(Input input, out Result result, out string error)
{
result = default;
error = string.Empty;
if (!EnsureRefpropInitialized(out var initErr))
{
error = initErr;
return false;
}
var w_W = input.HvPower_W;
if (!double.IsNaN(w_W) && !double.IsInfinity(w_W) && w_W == 0)
{
result = new Result(
heatingCapacityQh_kW: 0,
coolingCapacityQc_kW: 0,
copHeating: 0,
copCooling: 0,
isentropicEfficiencyPct: 0,
volumetricEfficiencyPct: 0,
mRef_kg_s: 0,
w_kW: 0,
h1_kJkg: 0,
s1_JmolK: 0,
v1_m3kg: 0,
h2_kJkg: 0,
h3_kJkg: 0,
h2s_kJkg: 0);
return true;
}
if (!TryGetCompressorPower_kW(input, out var w_kW, out var wErr))
{
error = wErr;
return false;
}
if (!TryGetRefrigerantMassFlow_kg_s(input, out var mRef_kg_s, out var mRefErr))
{
error = mRefErr;
return false;
}
if (!TryGetVaporPointState_ByTP_BarA_C(input.SuctionPress_BarA, input.SuctionTemp_C, out var h1_kJkg, out var s1_JmolK, out var v1_m3kg, out var p1Err))
{
error = $"h1/s1/吸气比容计算失败: {p1Err}";
return false;
}
if (!TryGetVaporPointEnthalpy_ByTP_BarA_C(input.DischargePress_BarA, input.DischargeTemp_C, out var h2_kJkg, out var p2Err))
{
error = $"h2 计算失败: {p2Err}";
return false;
}
double txvFrTempForH3_C = input.TxvFrTemp_C;
if (TryGetTxvFrTempForH3_ByDischargePress_BarA(input.DischargePress_BarA, out var derivedTxvFrTempForH3_C, out var satWarn))
{
txvFrTempForH3_C = derivedTxvFrTempForH3_C;
}
else if (!string.IsNullOrWhiteSpace(satWarn))
{
error = string.IsNullOrWhiteSpace(error)
? $"h3温度改用SATP(排气压力)计算Tsat失败已回退使用TxvFrTemp_C。原因: {satWarn}"
: $"{error}; h3温度改用SATP(排气压力)计算Tsat失败已回退使用TxvFrTemp_C。原因: {satWarn}";
}
if (!TryGetLiquidPointEnthalpy_ByTP_BarA_C(input.TxvFrPress_BarA, txvFrTempForH3_C, out var h3_kJkg, out var p3Err))
{
error = $"h3 计算失败: {p3Err}";
return false;
}
if (!TryGetIsentropicOutletEnthalpy_h2s_ByP2AndS1_BarA(input.DischargePress_BarA, s1_JmolK, out var h2s_kJkg, out var h2sErr))
{
error = $"h2s 计算失败: {h2sErr}";
return false;
}
if (!TryComputeCapacitiesAndCOP(mRef_kg_s, h1_kJkg, h2_kJkg, h3_kJkg, w_kW, out var qh_kW, out var qc_kW, out var copH, out var copC, out var capErr))
{
error = capErr;
return false;
}
if (!TryComputeIsentropicEfficiencyPct(mRef_kg_s, h1_kJkg, h2s_kJkg, w_kW, out var etaS_pct, out var etaSErr))
{
error = etaSErr;
return false;
}
if (!TryComputeVolumetricEfficiencyPct(mRef_kg_s, v1_m3kg, input.Speed_rpm, input.Displacement_cc, out var etaV_pct, out var etaVErr))
{
result = new Result(
heatingCapacityQh_kW: qh_kW,
coolingCapacityQc_kW: qc_kW,
copHeating: copH,
copCooling: copC,
isentropicEfficiencyPct: etaS_pct,
volumetricEfficiencyPct: double.NaN,
mRef_kg_s: mRef_kg_s,
w_kW: w_kW,
h1_kJkg: h1_kJkg,
s1_JmolK: s1_JmolK,
v1_m3kg: v1_m3kg,
h2_kJkg: h2_kJkg,
h3_kJkg: h3_kJkg,
h2s_kJkg: h2s_kJkg);
error = etaVErr;
return true;
}
result = new Result(
heatingCapacityQh_kW: qh_kW,
coolingCapacityQc_kW: qc_kW,
copHeating: copH,
copCooling: copC,
isentropicEfficiencyPct: etaS_pct,
volumetricEfficiencyPct: etaV_pct,
mRef_kg_s: mRef_kg_s,
w_kW: w_kW,
h1_kJkg: h1_kJkg,
s1_JmolK: s1_JmolK,
v1_m3kg: v1_m3kg,
h2_kJkg: h2_kJkg,
h3_kJkg: h3_kJkg,
h2s_kJkg: h2s_kJkg);
return true;
}
/// <summary>
/// 输出调试快照到 Console/Debug用于人工对比验证
/// </summary>
/// <param name="title">标题/阶段标识。</param>
/// <param name="input">输入。</param>
/// <param name="result">输出结果(可为 null表示计算失败时仅输出输入。</param>
/// <param name="error">错误/警告。</param>
public static void PrintDebugSnapshotToConsole(string title, Input input, Result? result, string error)
{
void Print(string line)
{
try { Debug.WriteLine(line); } catch { }
try { Console.WriteLine(line); } catch { }
}
Print($"================ {title} ================");
Print("--- Inputs ---");
Print($"Suction : T1={input.SuctionTemp_C} °C, P1={input.SuctionPress_BarA} BarA");
Print($"Discharge : T2={input.DischargeTemp_C} °C, P2={input.DischargePress_BarA} BarA");
Print($"TXV-before : T3={input.TxvFrTemp_C} °C, P3={input.TxvFrPress_BarA} BarA");
Print($"Flow : mTotal={input.TotalFlow_kg_h} kg/h");
Print($"Power(HV) : W={input.HvPower_W} W");
Print($"Speed : n={input.Speed_rpm} rpm");
Print($"Disp : disp={input.Displacement_cc} cc");
if (result.HasValue)
{
var r = result.Value;
Print("--- Intermediate (computed) ---");
Print($"mRef={r.MRef_kg_s:F8} kg/s, W={r.W_kW:F6} kW");
Print($"h1={r.H1_kJkg:F6} kJ/kg");
Print($"s1={r.S1_JmolK:F6} J/(mol·K)");
Print($"v1={r.V1_m3kg:F8} m3/kg");
Print($"h2={r.H2_kJkg:F6} kJ/kg");
Print($"h3={r.H3_kJkg:F6} kJ/kg");
Print($"h2s={r.H2s_kJkg:F6} kJ/kg");
Print("--- Final (computed) ---");
Print($"Qc={r.CoolingCapacityQc_kW:F5} kW");
Print($"COP(cool)={r.COPCooling:F5}");
Print($"Qh={r.HeatingCapacityQh_kW:F5} kW");
Print($"COP(heat)={r.COPHeating:F5}");
Print($"etaS={r.IsentropicEfficiencyPct:F4} %");
Print($"etaV={r.VolumetricEfficiencyPct:F3} %");
}
if (!string.IsNullOrWhiteSpace(error))
{
Print($"--- Error/Warning ---\r\n{error}");
}
Print("====================================================");
}
private bool EnsureRefpropInitialized(out string error)
{
error = string.Empty;
if (_rpInitialized) return true;
try
{
lock (_refpropLock)
{
if (_rpInitialized) return true;
string hpath = ConfigHelper.GetValue("FluidsPath");
if (string.IsNullOrWhiteSpace(hpath)) hpath = @".\PPCalculation\REFPROP\FLUIDS";
string configuredCryogen = ConfigHelper.GetValue("Cryogen");
if (string.IsNullOrWhiteSpace(configuredCryogen)) configuredCryogen = "R134a";
string hfldCore = configuredCryogen.Equals("R134a", StringComparison.OrdinalIgnoreCase)
? "R134A.FLD"
: "R134A.FLD";
long size = hpath.Length;
string hpathPadded = hpath + new string(' ', Math.Max(0, 255 - (int)size));
IRefProp64.SETPATHdll(hpathPadded, ref size);
long numComps = 1;
string hfld = hfldCore;
size = hfld.Length;
string hfldPadded = hfld + new string(' ', Math.Max(0, 10000 - (int)size));
string hfmix = "hmx.bnc" + new string(' ', 255);
string hrf = "DEF";
string herr = new string(' ', 255);
long ierr = 0;
long hfldLen = hfldPadded.Length, hfmixLen = hfmix.Length, hrfLen = hrf.Length, herrLen = herr.Length;
IRefProp64.SETUPdll(ref numComps, ref hfldPadded, ref hfmix, ref hrf,
ref ierr, ref herr, ref hfldLen, ref hfmixLen, ref hrfLen, ref herrLen);
if (ierr != 0)
{
error = $"REFPROP 初始化失败: {herr.Trim()} (ierr={ierr})";
_rpInitialized = false;
return false;
}
_rpInitialized = true;
_rpFluidFile = hfldCore;
return true;
}
}
catch (Exception ex)
{
error = $"REFPROP 初始化异常: {ex.Message}";
_rpInitialized = false;
return false;
}
}
private static double GetMolarMass()
{
double wmm = 0, Trp = 0, Tnbpt = 0, Tc = 0, Pc = 0, Dc = 0, Zc = 0, acf = 0, dip = 0, Rgas = 0;
long componentId = 1;
IRefProp64.INFOdll(ref componentId, ref wmm, ref Trp, ref Tnbpt, ref Tc, ref Pc, ref Dc, ref Zc, ref acf, ref dip, ref Rgas);
return wmm * 0.001;
}
private bool TryGetCompressorPower_kW(Input input, out double w_kW, out string error)
{
w_kW = double.NaN;
error = string.Empty;
double w_W = input.HvPower_W;
if (double.IsNaN(w_W) || double.IsInfinity(w_W) || w_W <= 0)
{
error = $"无效压缩机功率 HV[W]={w_W}";
return false;
}
w_kW = w_W / 1000.0;
return true;
}
private bool TryGetRefrigerantMassFlow_kg_s(Input input, out double mRef_kg_s, out string error)
{
mRef_kg_s = double.NaN;
error = string.Empty;
double mTotal_kg_h = input.TotalFlow_kg_h;
if (double.IsNaN(mTotal_kg_h) || double.IsInfinity(mTotal_kg_h))
{
error = "总流量(冷媒流量)为 NaN/Inf";
return false;
}
double mRef_kg_h = mTotal_kg_h;
if (mRef_kg_h <= 0)
{
error = $"冷媒质量流量<=0总流量={mTotal_kg_h}kg/h";
return false;
}
mRef_kg_s = mRef_kg_h / 3600.0;
return true;
}
private bool TryGetVaporPointEnthalpy_ByTP_BarA_C(double pressureBarA, double temperatureC, out double h_kJkg, out string error)
{
h_kJkg = double.NaN;
error = string.Empty;
if (!TryTPFLSH_ByTP_BarA_C(pressureBarA, temperatureC, out _, out var h_Jmol, out _, out _, out var flashErr))
{
error = flashErr;
return false;
}
if (!TryConvertH_Jmol_To_kJkg(h_Jmol, out h_kJkg, out var hErr))
{
error = hErr;
return false;
}
return true;
}
private bool TryGetLiquidPointEnthalpy_ByTP_BarA_C(double pressureBarA, double temperatureC, out double h_kJkg, out string error)
{
h_kJkg = double.NaN;
error = string.Empty;
double pMPa = pressureBarA * 0.1;
if (!TryTPRHO_LiquidDensity_ByTP_MPa_C(pMPa, temperatureC, out var d_molL, out var dErr))
{
error = dErr;
return false;
}
if (!TryTHERM_LiquidEnthalpy_ByTD(temperatureC, d_molL, out h_kJkg, out var hErr))
{
error = hErr;
return false;
}
return true;
}
private bool TryGetVaporPointState_ByTP_BarA_C(
double pressureBarA,
double temperatureC,
out double h_kJkg,
out double s_JmolK,
out double v_m3kg,
out string error)
{
h_kJkg = double.NaN;
s_JmolK = double.NaN;
v_m3kg = double.NaN;
error = string.Empty;
if (!TryTPFLSH_ByTP_BarA_C(pressureBarA, temperatureC, out var d_molL, out var h_Jmol, out var sOut_JmolK, out _, out var flashErr))
{
error = flashErr;
return false;
}
if (!TryConvertH_Jmol_To_kJkg(h_Jmol, out h_kJkg, out var hErr))
{
error = hErr;
return false;
}
s_JmolK = sOut_JmolK;
if (double.IsNaN(s_JmolK) || double.IsInfinity(s_JmolK))
{
error = "无效吸气熵";
return false;
}
if (!TryConvertMolarDensityToSpecificVolume(d_molL, out v_m3kg, out var vErr))
{
error = vErr;
return false;
}
return true;
}
private bool TryGetIsentropicOutletEnthalpy_h2s_ByP2AndS1_BarA(double dischargePressureBarA, double suctionEntropy_JmolK, out double h2s_kJkg, out string error)
{
h2s_kJkg = double.NaN;
error = string.Empty;
if (!EnsureRefpropInitialized(out var initErr))
{
error = initErr;
return false;
}
double pKPa = dischargePressureBarA * 100.0;
if (pKPa <= 0)
{
error = $"无效排气压力: {dischargePressureBarA} BarA";
return false;
}
if (double.IsNaN(suctionEntropy_JmolK) || double.IsInfinity(suctionEntropy_JmolK))
{
error = "无效吸气熵 s1";
return false;
}
double s_JmolK = suctionEntropy_JmolK;
double[] z = new double[20];
z[0] = 1.0;
double t = 0.0;
double d = 0.0;
double Dl = 0.0;
double Dv = 0.0;
double[] xliq = new double[20];
double[] xvap = new double[20];
double q = 0.0;
double ee = 0.0;
double h = 0.0;
double Cv = 0.0;
double Cp = 0.0;
double w = 0.0;
long ierr = 0;
long herrLen = 255;
string herr = new string(' ', 255);
lock (_refpropLock)
{
IRefProp64.PSFLSHdll(ref pKPa, ref s_JmolK, z, ref t, ref d, ref Dl, ref Dv, xliq, xvap, ref q, ref ee, ref h, ref Cv, ref Cp, ref w, ref ierr, ref herr, ref herrLen);
}
if (ierr != 0)
{
error = $"PSFLSH 错误: {herr.Trim()} (ierr={ierr})";
return false;
}
if (!TryConvertH_Jmol_To_kJkg(h, out h2s_kJkg, out var hConvErr))
{
error = hConvErr;
return false;
}
return true;
}
private bool TryComputeCapacitiesAndCOP(
double mRef_kg_s,
double h1_kJkg,
double h2_kJkg,
double h3_kJkg,
double w_kW,
out double qh_kW,
out double qc_kW,
out double copHeating,
out double copCooling,
out string error)
{
qh_kW = double.NaN;
qc_kW = double.NaN;
copHeating = double.NaN;
copCooling = double.NaN;
error = string.Empty;
if (mRef_kg_s <= 0 || double.IsNaN(mRef_kg_s) || double.IsInfinity(mRef_kg_s))
{
error = "无效冷媒质量流量";
return false;
}
if (w_kW <= 0 || double.IsNaN(w_kW) || double.IsInfinity(w_kW))
{
error = "无效压缩机功率";
return false;
}
qh_kW = mRef_kg_s * (h2_kJkg - h3_kJkg);
qc_kW = mRef_kg_s * (h1_kJkg - h3_kJkg);
copHeating = qh_kW / w_kW;
copCooling = qc_kW / w_kW;
return true;
}
private bool TryComputeIsentropicEfficiencyPct(double mRef_kg_s, double h1_kJkg, double h2s_kJkg, double w_kW, out double etaS_pct, out string error)
{
etaS_pct = double.NaN;
error = string.Empty;
if (double.IsNaN(mRef_kg_s) || double.IsInfinity(mRef_kg_s) || mRef_kg_s <= 0)
{
error = "无效冷媒质量流量";
return false;
}
if (double.IsNaN(w_kW) || double.IsInfinity(w_kW) || w_kW <= 0)
{
error = "无效压缩机功率";
return false;
}
double dh_isentropic = h2s_kJkg - h1_kJkg;
double eta = (mRef_kg_s * dh_isentropic) / w_kW;
if (double.IsNaN(eta) || double.IsInfinity(eta))
{
error = "等熵效率结果异常";
return false;
}
etaS_pct = eta * 100.0;
return true;
}
private bool TryComputeVolumetricEfficiencyPct(
double mRef_kg_s,
double v1_m3kg,
double speed_rpm,
double displacement_cc,
out double etaV_pct,
out string error)
{
etaV_pct = double.NaN;
error = string.Empty;
if (double.IsNaN(speed_rpm) || double.IsInfinity(speed_rpm) || speed_rpm <= 0)
{
error = $"无效转速: {speed_rpm} rpm";
return false;
}
if (double.IsNaN(displacement_cc) || double.IsInfinity(displacement_cc) || displacement_cc <= 0)
{
error = $"无效排量: {displacement_cc} cc";
return false;
}
if (double.IsNaN(v1_m3kg) || double.IsInfinity(v1_m3kg) || v1_m3kg <= 0)
{
error = "无效吸气比容";
return false;
}
if (double.IsNaN(mRef_kg_s) || double.IsInfinity(mRef_kg_s) || mRef_kg_s <= 0)
{
error = "无效冷媒质量流量";
return false;
}
double suctionVolFlow_m3_h = (mRef_kg_s * 3600.0) * v1_m3kg;
double theoVolFlow_m3_h = (speed_rpm / 60.0) * displacement_cc * 0.0036;
if (theoVolFlow_m3_h <= 0)
{
error = "理论吸气体积流量<=0";
return false;
}
etaV_pct = (suctionVolFlow_m3_h / theoVolFlow_m3_h) * 100.0;
return true;
}
private bool TryTPFLSH_ByTP_BarA_C(
double pressureBarA,
double temperatureC,
out double d_molL,
out double h_Jmol,
out double s_JmolK,
out double t_K,
out string error)
{
d_molL = double.NaN;
h_Jmol = double.NaN;
s_JmolK = double.NaN;
t_K = double.NaN;
error = string.Empty;
if (!EnsureRefpropInitialized(out var initErr))
{
error = initErr;
return false;
}
double t = temperatureC + 273.15;
double pKPa = pressureBarA * 100.0;
if (pKPa <= 0)
{
error = $"无效压力: {pressureBarA} BarA";
return false;
}
double[] x = new double[20];
x[0] = 1.0;
double d = 0.0;
double Dl = 0.0;
double Dv = 0.0;
double[] xliq = new double[20];
double[] xvap = new double[20];
double q = 0.0;
double ee = 0.0;
double h = 0.0;
double ss = 0.0;
double Cv = 0.0;
double Cp = 0.0;
double w = 0.0;
long ierr = 0;
long herrLen = 255;
string herr = new string(' ', 255);
lock (_refpropLock)
{
IRefProp64.TPFLSHdll(ref t, ref pKPa, x, ref d, ref Dl, ref Dv, xliq, xvap, ref q, ref ee, ref h, ref ss, ref Cv, ref Cp, ref w, ref ierr, ref herr, ref herrLen);
}
if (ierr != 0)
{
error = $"TPFLSH 错误: {herr.Trim()} (ierr={ierr})";
return false;
}
d_molL = d;
h_Jmol = h;
s_JmolK = ss;
t_K = t;
return true;
}
private bool TryConvertH_Jmol_To_kJkg(double h_Jmol, out double h_kJkg, out string error)
{
h_kJkg = double.NaN;
error = string.Empty;
double molarMassKgPerMol = GetMolarMass();
if (molarMassKgPerMol <= 0)
{
error = "无效的摩尔质量";
return false;
}
h_kJkg = (h_Jmol / molarMassKgPerMol) * 0.001;
return true;
}
private bool TryConvertMolarDensityToSpecificVolume(double d_molL, out double v_m3kg, out string error)
{
v_m3kg = double.NaN;
error = string.Empty;
if (double.IsNaN(d_molL) || double.IsInfinity(d_molL) || d_molL <= 0)
{
error = $"无效摩尔密度: {d_molL} mol/L";
return false;
}
double molarMassKgPerMol = GetMolarMass();
if (molarMassKgPerMol <= 0)
{
error = "无效的摩尔质量";
return false;
}
double rho_kg_m3 = d_molL * molarMassKgPerMol * 1000.0;
if (rho_kg_m3 <= 0)
{
error = $"无效密度: {rho_kg_m3} kg/m3";
return false;
}
v_m3kg = 1.0 / rho_kg_m3;
return true;
}
private bool TryTPRHO_LiquidDensity_ByTP_MPa_C(double pressureMPa, double temperatureC, out double densityMolPerL, out string error)
{
densityMolPerL = double.NaN;
error = string.Empty;
double tK = temperatureC + 273.15;
double pKPa = pressureMPa * 1000.0;
double[] x = new double[20];
x[0] = 1.0;
long kph = 1;
long kguess = 0;
double D = 0.0;
long ierr = 0;
long herrLen = 255;
string herr = new string(' ', 255);
lock (_refpropLock)
{
IRefProp64.TPRHOdll(ref tK, ref pKPa, x, ref kph, ref kguess, ref D, ref ierr, ref herr, ref herrLen);
}
if (ierr != 0)
{
error = $"TPRHO(液相) 错误: {herr.Trim()} (ierr={ierr})";
return false;
}
densityMolPerL = D;
return true;
}
private bool TryTHERM_LiquidEnthalpy_ByTD(double temperatureC, double densityMolPerL, out double h_liq_kJ_per_kg, out string error)
{
h_liq_kJ_per_kg = double.NaN;
error = string.Empty;
double tK = temperatureC + 273.15;
double D = densityMolPerL;
double[] x = new double[20];
x[0] = 1.0;
double pOut = 0, e = 0, hJmol = 0, sJmolK = 0, cv = 0, cp = 0, w = 0, hjt = 0;
double molarMassKgPerMol = GetMolarMass();
if (molarMassKgPerMol <= 0)
{
error = "无效的摩尔质量";
return false;
}
lock (_refpropLock)
{
IRefProp64.THERMdll(ref tK, ref D, x, ref pOut, ref e, ref hJmol, ref sJmolK, ref cv, ref cp, ref w, ref hjt);
}
h_liq_kJ_per_kg = (hJmol / molarMassKgPerMol) * 0.001;
return true;
}
private bool TrySATP_SaturationTemperatureK_ByP_BarA(double pressureBarA, out double tSatK, out string error)
{
tSatK = double.NaN;
error = string.Empty;
if (!EnsureRefpropInitialized(out var initErr))
{
error = initErr;
return false;
}
double pKPa = pressureBarA * 100.0;
if (pKPa <= 0)
{
error = $"无效压力: {pressureBarA} BarA";
return false;
}
double[] x = new double[20];
x[0] = 1.0;
long kph = 1;
double t = 0.0;
double Dl = 0.0;
double Dv = 0.0;
double[] xliq = new double[20];
double[] xvap = new double[20];
long ierr = 0;
long herrLen = 255;
string herr = new string(' ', 255);
lock (_refpropLock)
{
IRefProp64.SATPdll(ref pKPa, x, ref kph, ref t, ref Dl, ref Dv, xliq, xvap, ref ierr, ref herr, ref herrLen);
}
if (ierr != 0)
{
error = $"SATP 错误: {herr.Trim()} (ierr={ierr})";
return false;
}
tSatK = t;
return true;
}
private bool TryGetTxvFrTempForH3_ByDischargePress_BarA(double dischargePressBarA, out double txvFrTempForH3_C, out string warning)
{
txvFrTempForH3_C = double.NaN;
warning = string.Empty;
if (!TrySATP_SaturationTemperatureK_ByP_BarA(dischargePressBarA, out var tSatK, out var satErr))
{
warning = satErr;
return false;
}
double tSatC = tSatK - 273.15;
double offsetC = _h3TempOffset_C;
txvFrTempForH3_C = tSatC + offsetC;
return true;
}
/// <summary>
/// 生成一段便于保存/对比的文本报告。
/// </summary>
/// <param name="title">标题。</param>
/// <param name="input">输入。</param>
/// <param name="result">输出。</param>
/// <param name="error">错误/警告。</param>
/// <returns>报告文本。</returns>
public static string BuildDebugReport(string title, Input input, Result? result, string error)
{
var sb = new StringBuilder(512);
sb.AppendLine($"================ {title} ================");
sb.AppendLine("--- Inputs ---");
sb.AppendLine($"Suction : T1={input.SuctionTemp_C} °C, P1={input.SuctionPress_BarA} BarA");
sb.AppendLine($"Discharge : T2={input.DischargeTemp_C} °C, P2={input.DischargePress_BarA} BarA");
sb.AppendLine($"TXV-before : T3={input.TxvFrTemp_C} °C, P3={input.TxvFrPress_BarA} BarA");
sb.AppendLine($"Flow : mTotal={input.TotalFlow_kg_h} kg/h");
sb.AppendLine($"Power(HV) : W={input.HvPower_W} W");
sb.AppendLine($"Speed : n={input.Speed_rpm} rpm");
sb.AppendLine($"Disp : disp={input.Displacement_cc} cc");
if (result.HasValue)
{
var r = result.Value;
sb.AppendLine("--- Intermediate (computed) ---");
sb.AppendLine($"mRef={r.MRef_kg_s:F8} kg/s, W={r.W_kW:F6} kW");
sb.AppendLine($"h1={r.H1_kJkg:F6} kJ/kg");
sb.AppendLine($"s1={r.S1_JmolK:F6} J/(mol·K)");
sb.AppendLine($"v1={r.V1_m3kg:F8} m3/kg");
sb.AppendLine($"h2={r.H2_kJkg:F6} kJ/kg");
sb.AppendLine($"h3={r.H3_kJkg:F6} kJ/kg");
sb.AppendLine($"h2s={r.H2s_kJkg:F6} kJ/kg");
sb.AppendLine("--- Final (computed) ---");
sb.AppendLine($"Qc={r.CoolingCapacityQc_kW:F5} kW");
sb.AppendLine($"COP(cool)={r.COPCooling:F5}");
sb.AppendLine($"Qh={r.HeatingCapacityQh_kW:F5} kW");
sb.AppendLine($"COP(heat)={r.COPHeating:F5}");
sb.AppendLine($"etaS={r.IsentropicEfficiencyPct:F4} %");
sb.AppendLine($"etaV={r.VolumetricEfficiencyPct:F3} %");
}
if (!string.IsNullOrWhiteSpace(error))
{
sb.AppendLine("--- Error/Warning ---");
sb.AppendLine(error);
}
sb.AppendLine("====================================================");
return sb.ToString();
}
}
}