using CapMachine.Core;
using CapMachine.Wpf.PPCalculation;
using System;
namespace CapMachine.Wpf.Services
{
///
/// 六个热力结果值计算的输入数据。
///
///
/// 该输入对象对应六个结果值计算过程中用到的全部外部测点/配置量。
/// 所有字段均采用当前系统中已经约定好的工程单位,不在本对象中做任何换算。
///
public sealed class PPCThermodynamicSixResultsCalculationInput
{
///
/// 压缩机输入功率,单位 W。
/// 当前来源为 HV 功率标签。
///
public double CompressorPowerW { get; set; }
///
/// 总流量(冷媒流量标签当前语义),单位 kg/h。
/// 该值会与油流量做差,得到真正参与热力计算的冷媒质量流量。
///
public double TotalMassFlowKgPerHour { get; set; }
///
/// 润滑油流量,单位 kg/h。
///
public double OilMassFlowKgPerHour { get; set; }
///
/// 吸气压力,单位 BarA(绝压)。
///
public double SuctionPressureBarA { get; set; }
///
/// 吸气温度,单位 ℃。
///
public double SuctionTemperatureC { get; set; }
///
/// 排气压力,单位 BarA(绝压)。
///
public double DischargePressureBarA { get; set; }
///
/// 排气温度,单位 ℃。
///
public double DischargeTemperatureC { get; set; }
///
/// 膨胀阀前液路压力,单位 BarA(绝压)。
///
public double LiquidPressureBarA { get; set; }
///
/// 膨胀阀前液路温度,单位 ℃。
///
public double LiquidTemperatureC { get; set; }
///
/// 压缩机转速,单位 rpm。
/// 用于容积效率计算。
///
public double CompressorSpeedRpm { get; set; }
///
/// 压缩机单转排量,单位 cc。
/// 用于理论体积流量计算。
///
public double CompressorDisplacementCc { get; set; }
}
///
/// 六个热力结果值计算结果。
///
///
/// 默认均初始化为 ,用于明确区分“未成功得到结果”和“得到有效数值”。
///
public sealed class PPCThermodynamicSixResultsCalculationResult
{
///
/// 制热量 Qh,单位 kW。
/// 计算公式:Qh = mRef * (h2 - h3)。
///
public double HeatingCapacityQh_kW { get; set; } = double.NaN;
///
/// 制冷量 Qc,单位 kW。
/// 计算公式:Qc = mRef * (h1 - h3)。
///
public double CoolingCapacityQc_kW { get; set; } = double.NaN;
///
/// 制热 COP。
/// 计算公式:COPHeating = Qh / W。
///
public double COPHeating { get; set; } = double.NaN;
///
/// 制冷 COP。
/// 计算公式:COPCooling = Qc / W。
///
public double COPCooling { get; set; } = double.NaN;
///
/// 等熵效率,单位 %。
/// 计算公式:(h2s - h1) / (h2 - h1) * 100。
///
public double IsentropicEfficiencyPct { get; set; } = double.NaN;
///
/// 容积效率,单位 %。
/// 计算公式:实际吸气体积流量 / 理论吸气体积流量 * 100。
///
public double VolumetricEfficiencyPct { get; set; } = double.NaN;
}
///
/// 六个热力结果值独立计算类。
///
///
/// 本类负责以下六个结果的完整计算流程:
/// - 制热量
/// - COP(制热)
/// - 等熵效率
/// - 制冷量
/// - COP(制冷)
/// - 容积效率
///
/// 设计目标是把“结果计算逻辑”从 PPCService 中抽离出来,
/// 让服务层只负责取标签和写回,计算类只负责计算本身。
/// 为降低后续新增其他计算类时对已验算结果的影响范围,
/// 本类将自身所需的底层 REFPROP 支撑实现内聚在类内私有 support 中。
///
/// 当前实现严格保持既有流程不变:
/// 1. 由总流量和油流量得到冷媒质量流量
/// 2. 由吸气点得到 h1 / s1 / v1
/// 3. 由排气点得到 h2
/// 4. 由液路点得到 h3
/// 5. 由排气压力和吸气熵得到 h2s
/// 6. 计算 Qh / Qc / COP / 等熵效率 / 容积效率
///
public sealed class PPCThermodynamicSixResultsCalculator
{
///
/// 底层物性计算支持对象。
/// 负责提供 REFPROP 初始化与 TPRHO / THERM / PSFLSH 等共用能力。
///
private readonly LocalCalculationSupport _support;
///
/// 初始化六个热力结果值计算类。
///
public PPCThermodynamicSixResultsCalculator()
{
_support = new LocalCalculationSupport();
}
///
/// 按既定流程一次性计算六个热力结果值。
///
/// 输入数据,包含功率、流量、吸排气状态点、液路状态点、转速与排量。
/// 输出结果对象。
///
/// 错误或警告信息。
/// 当前逻辑中,若“容积效率”计算失败但其他 5 个结果成功,会返回 ,
/// 同时通过此参数把容积效率失败原因返回给上层,保持原有行为不变。
///
///
/// - :主要结果计算完成;容积效率可能成功也可能失败
/// - :关键输入或关键热力步骤失败
///
public bool TryCalculate(PPCThermodynamicSixResultsCalculationInput input, out PPCThermodynamicSixResultsCalculationResult result, out string error)
{
// 创建输出对象,并将错误文本清空。
result = new PPCThermodynamicSixResultsCalculationResult();
error = string.Empty;
// 所有物性函数调用之前,先确保 REFPROP 已完成初始化。
if (!_support.EnsureRefpropInitialized(out var initErr))
{
error = initErr;
return false;
}
// 第 1 步:将压缩机输入功率由 W 换算为 kW。
if (!TryGetCompressorPower_kW(input.CompressorPowerW, out var w_kW, out var wErr))
{
error = wErr;
return false;
}
// 第 2 步:根据“总流量 - 油流量”,得到真正参与循环的冷媒质量流量,
// 并从 kg/h 换算到后续公式使用的 kg/s。
if (!TryGetRefrigerantMassFlow_kg_s(input.TotalMassFlowKgPerHour, input.OilMassFlowKgPerHour, out var mRef_kg_s, out var mRefErr))
{
error = mRefErr;
return false;
}
// 第 3 步:由吸气压力/温度求出吸气点状态:
// - h1:吸气比焓
// - s1:吸气比熵
// - v1:吸气比容
if (!TryGetVaporPointState_ByTP_BarA_C(input.SuctionPressureBarA, input.SuctionTemperatureC, out var h1_kJkg, out var s1_kJkgK, out var v1_m3kg, out var p1Err))
{
error = $"h1/s1/吸气比容计算失败: {p1Err}";
return false;
}
// 第 4 步:由排气压力/温度求排气比焓 h2。
if (!TryGetVaporPointEnthalpy_ByTP_BarA_C(input.DischargePressureBarA, input.DischargeTemperatureC, out var h2_kJkg, out var p2Err))
{
error = $"h2 计算失败: {p2Err}";
return false;
}
// 第 5 步:由液路压力/温度求液路比焓 h3。
if (!TryGetLiquidPointEnthalpy_ByTP_BarA_C(input.LiquidPressureBarA, input.LiquidTemperatureC, out var h3_kJkg, out var p3Err))
{
error = $"h3 计算失败: {p3Err}";
return false;
}
// 第 6 步:由排气压力 P2 和吸气熵 s1 求等熵出口焓 h2s。
if (!_support.TryGetIsentropicOutletEnthalpy_h2s_ByP2AndS1_BarA(input.DischargePressureBarA, s1_kJkgK, out var h2s_kJkg, out var h2sErr))
{
error = $"h2s 计算失败: {h2sErr}";
return false;
}
// 第 7 步:计算 Qh、Qc、COP(制热)、COP(制冷)。
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;
}
// 第 8 步:计算等熵效率。
if (!TryComputeIsentropicEfficiencyPct(h1_kJkg, h2_kJkg, h2s_kJkg, out var etaS_pct, out var etaSErr))
{
error = etaSErr;
return false;
}
// 先写入 5 个关键结果。
result.HeatingCapacityQh_kW = qh_kW;
result.CoolingCapacityQc_kW = qc_kW;
result.COPHeating = copH;
result.COPCooling = copC;
result.IsentropicEfficiencyPct = etaS_pct;
// 最后再算容积效率。
// 当前逻辑特意保持与旧实现一致:
// 即使容积效率失败,只要前面 5 个主结果已经成功,就仍然返回 true,
// 同时把失败原因放到 error 中,供调用方决定是否记录为警告。
if (!TryComputeVolumetricEfficiencyPct(mRef_kg_s, v1_m3kg, input.CompressorSpeedRpm, input.CompressorDisplacementCc, out var etaV_pct, out var etaVErr))
{
error = etaVErr;
return true;
}
result.VolumetricEfficiencyPct = etaV_pct;
return true;
}
///
/// 获取压缩机输入功率并换算为 kW。
///
/// 输入功率,单位 W。
/// 输出功率,单位 kW。
/// 失败原因。
/// 是否换算成功。
private bool TryGetCompressorPower_kW(double compressorPowerW, out double w_kW, out string error)
{
w_kW = double.NaN;
error = string.Empty;
// 读取输入功率,并做基础合法性校验。
double w_W = compressorPowerW;
if (double.IsNaN(w_W) || double.IsInfinity(w_W) || w_W <= 0)
{
error = $"无效压缩机功率 HV[W]={w_W}";
return false;
}
// 六个热力结果公式里统一使用 kW,因此这里做 W -> kW 的标准换算。
w_kW = w_W / 1000.0;
return true;
}
///
/// 获取冷媒质量流量,输出单位 kg/s。
///
/// 总流量,单位 kg/h。
/// 油流量,单位 kg/h。
/// 冷媒质量流量输出,单位 kg/s。
/// 失败原因。
/// 是否计算成功。
///
/// 当前流程保持与图片/旧代码一致:
/// 1. 读取总流量 kg/h
/// 2. 读取油流量 kg/h
/// 3. 冷媒流量 = 总流量 - 油流量
/// 4. 再由 kg/h 换算为 kg/s
///
private bool TryGetRefrigerantMassFlow_kg_s(double totalMassFlowKgPerHour, double oilMassFlowKgPerHour, out double mRef_kg_s, out string error)
{
mRef_kg_s = double.NaN;
error = string.Empty;
// 先读取总流量。
if (!TryGetTotalMassFlow_kg_h(totalMassFlowKgPerHour, out var mTotal_kg_h, out var totalErr))
{
error = totalErr;
return false;
}
// 再读取油流量。
if (!TryGetOilMassFlow_kg_h(oilMassFlowKgPerHour, out var mOil_kg_h, out var oilErr))
{
error = oilErr;
return false;
}
// 计算真正参与循环的冷媒质量流量:mRef = mTotal - mOil。
if (!TryComputeRefrigerantMassFlow_kg_h(mTotal_kg_h, mOil_kg_h, out var mRef_kg_h, out var refErr))
{
error = refErr;
return false;
}
// 将 kg/h 换算成后续容量计算使用的 kg/s。
return TryConvertMassFlow_kg_h_To_kg_s(mRef_kg_h, out mRef_kg_s, out error);
}
///
/// 获取总流量,单位 kg/h。
///
/// 输入总流量。
/// 输出总流量。
/// 失败原因。
/// 是否读取成功。
private bool TryGetTotalMassFlow_kg_h(double totalMassFlowKgPerHour, out double mTotal_kg_h, out string error)
{
mTotal_kg_h = double.NaN;
error = string.Empty;
// 当前方法只做数值读取和合法性校验,不做其他换算。
mTotal_kg_h = totalMassFlowKgPerHour;
if (double.IsNaN(mTotal_kg_h) || double.IsInfinity(mTotal_kg_h))
{
error = "总流量(冷媒流量)为 NaN/Inf";
return false;
}
return true;
}
///
/// 获取油流量,单位 kg/h。
///
/// 输入油流量。
/// 输出油流量。
/// 失败原因。
/// 是否读取成功。
private bool TryGetOilMassFlow_kg_h(double oilMassFlowKgPerHour, out double mOil_kg_h, out string error)
{
mOil_kg_h = double.NaN;
error = string.Empty;
// 当前方法只做数值读取和合法性校验,不做其他换算。
mOil_kg_h = oilMassFlowKgPerHour;
if (double.IsNaN(mOil_kg_h) || double.IsInfinity(mOil_kg_h))
{
error = "油流量为 NaN/Inf";
return false;
}
return true;
}
///
/// 计算冷媒质量流量,单位 kg/h。
///
/// 总流量,单位 kg/h。
/// 油流量,单位 kg/h。
/// 冷媒质量流量输出,单位 kg/h。
/// 失败原因。
/// 是否计算成功。
private bool TryComputeRefrigerantMassFlow_kg_h(double mTotal_kg_h, double mOil_kg_h, out double mRef_kg_h, out string error)
{
mRef_kg_h = double.NaN;
error = string.Empty;
if (double.IsNaN(mTotal_kg_h) || double.IsInfinity(mTotal_kg_h))
{
error = "总流量(冷媒流量)为 NaN/Inf";
return false;
}
if (double.IsNaN(mOil_kg_h) || double.IsInfinity(mOil_kg_h))
{
error = "油流量为 NaN/Inf";
return false;
}
// 与既有实现一致:冷媒质量流量 = 总流量 - 油流量。
mRef_kg_h = mTotal_kg_h - mOil_kg_h;
if (mRef_kg_h <= 0)
{
error = $"冷媒质量流量<=0,总流量={mTotal_kg_h}kg/h,油流量={mOil_kg_h}kg/h";
return false;
}
return true;
}
///
/// 将质量流量从 kg/h 换算到 kg/s。
///
/// 输入质量流量,单位 kg/h。
/// 输出质量流量,单位 kg/s。
/// 失败原因。
/// 是否换算成功。
private bool TryConvertMassFlow_kg_h_To_kg_s(double massFlow_kg_h, out double massFlow_kg_s, out string error)
{
massFlow_kg_s = double.NaN;
error = string.Empty;
if (double.IsNaN(massFlow_kg_h) || double.IsInfinity(massFlow_kg_h) || massFlow_kg_h <= 0)
{
error = $"无效质量流量={massFlow_kg_h}kg/h";
return false;
}
// 1 小时 = 3600 秒,因此 kg/h -> kg/s 需要除以 3600。
massFlow_kg_s = massFlow_kg_h / 3600.0;
return true;
}
///
/// 由某一气相状态点的压力 / 温度求质量比焓。
///
/// 输入压力,单位 BarA(绝压)。
/// 输入温度,单位 ℃。
/// 输出质量比焓,单位 kJ/kg。
/// 失败原因。
/// 是否计算成功。
///
/// 当前流程:
/// 1. BarA -> MPa
/// 2. 用气相 TPRHO 求摩尔密度 D
/// 3. 用 THERM 求焓
///
private bool TryGetVaporPointEnthalpy_ByTP_BarA_C(double pressureBarA, double temperatureC, out double h_kJkg, out string error)
{
h_kJkg = double.NaN;
error = string.Empty;
// 物性 helper 的压力输入单位是 MPa,因此先换算。
double pMPa = pressureBarA * 0.1;
// 先求气相摩尔密度 D。
if (!_support.TryTPRHO_VaporDensity_ByTP_MPa_C(pMPa, temperatureC, out var d_molL, out var dErr))
{
error = dErr;
return false;
}
// THERM helper 的温度输入为 K,因此把 ℃ 转成 K 后再求焓。
double tK = temperatureC + 273.15;
if (!_support.TryTHERM_Enthalpy_kJkg_ByT_K_D(tK, d_molL, out h_kJkg, out var hErr))
{
error = hErr;
return false;
}
return true;
}
///
/// 由某一液相状态点的压力 / 温度求质量比焓。
///
/// 输入压力,单位 BarA(绝压)。
/// 输入温度,单位 ℃。
/// 输出质量比焓,单位 kJ/kg。
/// 失败原因。
/// 是否计算成功。
private bool TryGetLiquidPointEnthalpy_ByTP_BarA_C(double pressureBarA, double temperatureC, out double h_kJkg, out string error)
{
h_kJkg = double.NaN;
error = string.Empty;
// 物性 helper 的压力输入单位是 MPa,因此先换算。
double pMPa = pressureBarA * 0.1;
// 先按液相路径求摩尔密度 D。
if (!_support.TryTPRHO_LiquidDensity_ByTP_MPa_C(pMPa, temperatureC, out var d_molL, out var dErr))
{
error = dErr;
return false;
}
// 再按液相路径求质量比焓 h。
if (!_support.TryTHERM_LiquidEnthalpy_ByTD(temperatureC, d_molL, out h_kJkg, out var hErr))
{
error = hErr;
return false;
}
return true;
}
///
/// 由某一气相状态点的压力 / 温度联合求取 h、s、v。
///
/// 输入压力,单位 BarA(绝压)。
/// 输入温度,单位 ℃。
/// 输出质量比焓,单位 kJ/kg。
/// 输出质量比熵,单位 kJ/(kg·K)。
/// 输出比容,单位 m³/kg。
/// 失败原因。
/// 是否计算成功。
private bool TryGetVaporPointState_ByTP_BarA_C(double pressureBarA, double temperatureC, out double h_kJkg, out double s_kJkgK, out double v_m3kg, out string error)
{
h_kJkg = double.NaN;
s_kJkgK = double.NaN;
v_m3kg = double.NaN;
error = string.Empty;
// 第一步:BarA -> MPa。
double pMPa = pressureBarA * 0.1;
// 第二步:由气相 TPRHO 求摩尔密度 D。
if (!_support.TryTPRHO_VaporDensity_ByTP_MPa_C(pMPa, temperatureC, out var d_molL, out var dErr))
{
error = dErr;
return false;
}
// 第三步:用 THERM 求吸气点比焓 h1。
double tK = temperatureC + 273.15;
if (!_support.TryTHERM_Enthalpy_kJkg_ByT_K_D(tK, d_molL, out h_kJkg, out var hErr))
{
error = hErr;
return false;
}
// 第四步:用 THERM 求吸气点比熵 s1。
if (!_support.TryTHERM_VaporEntropy_ByTD(temperatureC, d_molL, out s_kJkgK, out var sErr))
{
error = sErr;
return false;
}
// 第五步:由摩尔密度换算为质量比容 v1。
if (!_support.TryConvertMolarDensityToSpecificVolume(d_molL, out v_m3kg, out var vErr))
{
error = vErr;
return false;
}
return true;
}
///
/// 统一计算制热量、制冷量、制热 COP、制冷 COP。
///
/// 冷媒质量流量,单位 kg/s。
/// 吸气比焓,单位 kJ/kg。
/// 排气比焓,单位 kJ/kg。
/// 液路比焓,单位 kJ/kg。
/// 压缩机功率,单位 kW。
/// 制热量输出,单位 kW。
/// 制冷量输出,单位 kW。
/// 制热 COP 输出。
/// 制冷 COP 输出。
/// 失败原因。
/// 是否计算成功。
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;
// 先算制热量:Qh = mRef * (h2 - h3)。
if (!TryComputeHeatingCapacityQh_kW(mRef_kg_s, h2_kJkg, h3_kJkg, out qh_kW, out var qhErr))
{
error = qhErr;
return false;
}
// 再算制冷量:Qc = mRef * (h1 - h3)。
if (!TryComputeCoolingCapacityQc_kW(mRef_kg_s, h1_kJkg, h3_kJkg, out qc_kW, out var qcErr))
{
error = qcErr;
return false;
}
// 制热 COP = Qh / W。
if (!TryComputeHeatingCOP(qh_kW, w_kW, out copHeating, out var copHErr))
{
error = copHErr;
return false;
}
// 制冷 COP = Qc / W。
if (!TryComputeCoolingCOP(qc_kW, w_kW, out copCooling, out var copCErr))
{
error = copCErr;
return false;
}
return true;
}
///
/// 计算焓差,单位 kJ/kg。
///
/// 被减数,单位 kJ/kg。
/// 减数,单位 kJ/kg。
/// 当前计算量名称,用于拼接错误信息。
/// 焓差输出,单位 kJ/kg。
/// 失败原因。
/// 是否计算成功。
private bool TryComputeEnthalpyDifference_kJkg(double minuend_kJkg, double subtrahend_kJkg, string quantityName, out double deltaH_kJkg, out string error)
{
deltaH_kJkg = double.NaN;
error = string.Empty;
// 先校验输入两端焓值是否有效。
if (double.IsNaN(minuend_kJkg) || double.IsInfinity(minuend_kJkg) || double.IsNaN(subtrahend_kJkg) || double.IsInfinity(subtrahend_kJkg))
{
error = $"{quantityName}输入存在 NaN/Inf";
return false;
}
// 焓差按“被减数 - 减数”计算。
deltaH_kJkg = minuend_kJkg - subtrahend_kJkg;
if (double.IsNaN(deltaH_kJkg) || double.IsInfinity(deltaH_kJkg))
{
error = $"{quantityName}结果异常";
return false;
}
return true;
}
///
/// 根据质量流量与焓差计算容量,单位 kW。
///
/// 冷媒质量流量,单位 kg/s。
/// 焓差,单位 kJ/kg。
/// 容量名称,用于错误信息。
/// 容量输出,单位 kW。
/// 失败原因。
/// 是否计算成功。
///
/// 公式:Capacity = mRef * Δh。
/// 因为 kg/s * kJ/kg = kJ/s = kW,所以结果天然就是 kW。
///
private bool TryComputeCapacity_kW(double mRef_kg_s, double deltaH_kJkg, string quantityName, out double capacity_kW, out string error)
{
capacity_kW = 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(deltaH_kJkg) || double.IsInfinity(deltaH_kJkg))
{
error = $"{quantityName}焓差异常";
return false;
}
// 按容量公式直接计算。
capacity_kW = mRef_kg_s * deltaH_kJkg;
if (double.IsNaN(capacity_kW) || double.IsInfinity(capacity_kW))
{
error = $"{quantityName}结果异常";
return false;
}
return true;
}
///
/// 计算制热量 Qh,单位 kW。
///
/// 冷媒质量流量,单位 kg/s。
/// 排气比焓 h2,单位 kJ/kg。
/// 液路比焓 h3,单位 kJ/kg。
/// 制热量输出,单位 kW。
/// 失败原因。
/// 是否计算成功。
private bool TryComputeHeatingCapacityQh_kW(double mRef_kg_s, double h2_kJkg, double h3_kJkg, out double qh_kW, out string error)
{
qh_kW = double.NaN;
error = string.Empty;
// 先计算制热焓差:(h2 - h3)。
if (!TryComputeEnthalpyDifference_kJkg(h2_kJkg, h3_kJkg, "制热焓差(h2-h3)", out var deltaH_kJkg, out var deltaErr))
{
error = deltaErr;
return false;
}
// 再由质量流量与焓差得到制热量。
return TryComputeCapacity_kW(mRef_kg_s, deltaH_kJkg, "制热量Qh", out qh_kW, out error);
}
///
/// 计算制冷量 Qc,单位 kW。
///
/// 冷媒质量流量,单位 kg/s。
/// 吸气比焓 h1,单位 kJ/kg。
/// 液路比焓 h3,单位 kJ/kg。
/// 制冷量输出,单位 kW。
/// 失败原因。
/// 是否计算成功。
private bool TryComputeCoolingCapacityQc_kW(double mRef_kg_s, double h1_kJkg, double h3_kJkg, out double qc_kW, out string error)
{
qc_kW = double.NaN;
error = string.Empty;
// 先计算制冷焓差:(h1 - h3)。
if (!TryComputeEnthalpyDifference_kJkg(h1_kJkg, h3_kJkg, "制冷焓差(h1-h3)", out var deltaH_kJkg, out var deltaErr))
{
error = deltaErr;
return false;
}
// 再由质量流量与焓差得到制冷量。
return TryComputeCapacity_kW(mRef_kg_s, deltaH_kJkg, "制冷量Qc", out qc_kW, out error);
}
///
/// 计算 COP。
///
/// 容量,单位 kW。
/// 压缩机输入功率,单位 kW。
/// 当前 COP 名称,用于错误信息。
/// COP 输出。
/// 失败原因。
/// 是否计算成功。
private bool TryComputeCOP(double capacity_kW, double w_kW, string quantityName, out double cop, out string error)
{
cop = double.NaN;
error = string.Empty;
// 容量必须是有效数值。
if (double.IsNaN(capacity_kW) || double.IsInfinity(capacity_kW))
{
error = $"{quantityName}输入异常";
return false;
}
// 功率必须有效且大于 0,避免除零。
if (double.IsNaN(w_kW) || double.IsInfinity(w_kW) || w_kW <= 0)
{
error = "无效压缩机功率";
return false;
}
// COP = 容量 / 输入功率。
cop = capacity_kW / w_kW;
if (double.IsNaN(cop) || double.IsInfinity(cop))
{
error = $"{quantityName}结果异常";
return false;
}
return true;
}
///
/// 计算制热 COP。
///
/// 制热量,单位 kW。
/// 压缩机输入功率,单位 kW。
/// 制热 COP 输出。
/// 失败原因。
/// 是否计算成功。
private bool TryComputeHeatingCOP(double qh_kW, double w_kW, out double copHeating, out string error)
{
return TryComputeCOP(qh_kW, w_kW, "COP(制热)", out copHeating, out error);
}
///
/// 计算制冷 COP。
///
/// 制冷量,单位 kW。
/// 压缩机输入功率,单位 kW。
/// 制冷 COP 输出。
/// 失败原因。
/// 是否计算成功。
private bool TryComputeCoolingCOP(double qc_kW, double w_kW, out double copCooling, out string error)
{
return TryComputeCOP(qc_kW, w_kW, "COP(制冷)", out copCooling, out error);
}
///
/// 计算等熵效率,单位 %。
///
/// 吸气比焓 h1,单位 kJ/kg。
/// 实际排气比焓 h2,单位 kJ/kg。
/// 等熵出口比焓 h2s,单位 kJ/kg。
/// 等熵效率输出,单位 %。
/// 失败原因。
/// 是否计算成功。
private bool TryComputeIsentropicEfficiencyPct(double h1_kJkg, double h2_kJkg, double h2s_kJkg, out double etaS_pct, out string error)
{
etaS_pct = double.NaN;
error = string.Empty;
// 实际压缩焓升:(h2 - h1)。
if (!TryComputeEnthalpyDifference_kJkg(h2_kJkg, h1_kJkg, "实际压缩焓升(h2-h1)", out var actualRise_kJkg, out var actualErr))
{
error = actualErr;
return false;
}
// 等熵压缩焓升:(h2s - h1)。
if (!TryComputeEnthalpyDifference_kJkg(h2s_kJkg, h1_kJkg, "等熵压缩焓升(h2s-h1)", out var isentropicRise_kJkg, out var isoErr))
{
error = isoErr;
return false;
}
// 等熵效率 = 等熵焓升 / 实际焓升 * 100%。
return TryComputeEfficiencyPct(isentropicRise_kJkg, actualRise_kJkg, "等熵效率", out etaS_pct, out error);
}
///
/// 计算容积效率,单位 %。
///
/// 冷媒质量流量,单位 kg/s。
/// 吸气比容 v1,单位 m³/kg。
/// 压缩机转速,单位 rpm。
/// 压缩机排量,单位 cc。
/// 容积效率输出,单位 %。
/// 失败原因。
/// 是否计算成功。
private bool TryComputeVolumetricEfficiencyPct(double mRef_kg_s, double v1_m3kg, double speed_rpm, double disp_cc, out double etaV_pct, out string error)
{
etaV_pct = double.NaN;
error = string.Empty;
// 先校验转速。
if (!TryGetCompressorSpeed_rpm(speed_rpm, out var validatedSpeed_rpm, out var speedErr))
{
error = speedErr;
return false;
}
// 再校验排量。
if (!TryGetCompressorDisplacement_cc(disp_cc, out var validatedDisp_cc, out var dispErr))
{
error = dispErr;
return false;
}
// 计算实际吸气体积流量。
if (!TryComputeSuctionVolumeFlow_m3_h(mRef_kg_s, v1_m3kg, out var suctionVolFlow_m3_h, out var suctionErr))
{
error = suctionErr;
return false;
}
// 计算理论吸气体积流量。
if (!TryComputeTheoreticalVolumeFlow_m3_h(validatedSpeed_rpm, validatedDisp_cc, out var theoVolFlow_m3_h, out var theoErr))
{
error = theoErr;
return false;
}
// 容积效率 = 实际吸气体积流量 / 理论吸气体积流量 * 100%。
return TryComputeEfficiencyPct(suctionVolFlow_m3_h, theoVolFlow_m3_h, "容积效率", out etaV_pct, out error);
}
///
/// 计算百分比效率。
///
/// 分子。
/// 分母。
/// 当前效率名称,用于错误信息。
/// 效率输出,单位 %。
/// 失败原因。
/// 是否计算成功。
private bool TryComputeEfficiencyPct(double numerator, double denominator, string quantityName, out double efficiencyPct, out string error)
{
efficiencyPct = double.NaN;
error = string.Empty;
// 先校验分子。
if (double.IsNaN(numerator) || double.IsInfinity(numerator))
{
error = $"{quantityName}分子异常";
return false;
}
// 再校验分母,避免除零或极小数造成结果发散。
const double eps = 1e-9;
if (double.IsNaN(denominator) || double.IsInfinity(denominator) || Math.Abs(denominator) < eps)
{
error = $"{quantityName}分母过小或异常";
return false;
}
// 效率 = 分子 / 分母。
double efficiency = numerator / denominator;
if (double.IsNaN(efficiency) || double.IsInfinity(efficiency))
{
error = $"{quantityName}结果异常";
return false;
}
// 将无量纲效率换算为百分数。
efficiencyPct = efficiency * 100.0;
return true;
}
///
/// 获取并校验压缩机转速,单位 rpm。
///
/// 输入转速,单位 rpm。
/// 输出转速,单位 rpm。
/// 失败原因。
/// 是否获取成功。
private bool TryGetCompressorSpeed_rpm(double compressorSpeedRpm, out double speed_rpm, out string error)
{
speed_rpm = double.NaN;
error = string.Empty;
// 当前方法只做读取与合法性校验。
speed_rpm = compressorSpeedRpm;
if (double.IsNaN(speed_rpm) || double.IsInfinity(speed_rpm) || speed_rpm <= 0)
{
error = $"无效转速: {speed_rpm} rpm";
return false;
}
return true;
}
///
/// 计算实际吸气体积流量,单位 m³/h。
///
/// 冷媒质量流量,单位 kg/s。
/// 吸气比容,单位 m³/kg。
/// 实际吸气体积流量输出,单位 m³/h。
/// 失败原因。
/// 是否计算成功。
private bool TryComputeSuctionVolumeFlow_m3_h(double mRef_kg_s, double v1_m3kg, out double suctionVolFlow_m3_h, out string error)
{
suctionVolFlow_m3_h = 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(v1_m3kg) || double.IsInfinity(v1_m3kg) || v1_m3kg <= 0)
{
error = "无效吸气比容";
return false;
}
// 实际吸气体积流量 = (kg/s * 3600) * m³/kg = m³/h。
suctionVolFlow_m3_h = (mRef_kg_s * 3600.0) * v1_m3kg;
if (double.IsNaN(suctionVolFlow_m3_h) || double.IsInfinity(suctionVolFlow_m3_h))
{
error = "实际吸气体积流量结果异常";
return false;
}
return true;
}
///
/// 计算理论吸气体积流量,单位 m³/h。
///
/// 压缩机转速,单位 rpm。
/// 压缩机排量,单位 cc。
/// 理论吸气体积流量输出,单位 m³/h。
/// 失败原因。
/// 是否计算成功。
///
/// 当前公式保持原实现不变:
/// (speed_rpm / 60.0) * disp_cc * 0.0036
///
private bool TryComputeTheoreticalVolumeFlow_m3_h(double speed_rpm, double disp_cc, out double theoVolFlow_m3_h, out string error)
{
theoVolFlow_m3_h = 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(disp_cc) || double.IsInfinity(disp_cc) || disp_cc <= 0)
{
error = $"无效压缩机排量: {disp_cc} cc";
return false;
}
// 理论体积流量公式保持原有写法不变。
theoVolFlow_m3_h = (speed_rpm / 60.0) * disp_cc * 0.0036;
if (double.IsNaN(theoVolFlow_m3_h) || double.IsInfinity(theoVolFlow_m3_h) || theoVolFlow_m3_h <= 0)
{
error = "理论吸气体积流量<=0";
return false;
}
return true;
}
///
/// 获取并校验压缩机排量,单位 cc。
///
/// 输入排量,单位 cc。
/// 输出排量,单位 cc。
/// 失败原因。
/// 是否获取成功。
private bool TryGetCompressorDisplacement_cc(double compressorDisplacementCc, out double displacement_cc, out string error)
{
displacement_cc = double.NaN;
error = string.Empty;
// 当前方法只做读取与合法性校验。
displacement_cc = compressorDisplacementCc;
if (double.IsNaN(displacement_cc) || double.IsInfinity(displacement_cc) || displacement_cc <= 0)
{
error = $"压缩机排量<=0: {displacement_cc}";
return false;
}
return true;
}
///
/// 六个热力结果计算类私有的底层物性支持实现。
///
///
/// 该实现仅服务当前六结果计算类,不与其他结果类共享实现细节,
/// 这样即使后续为了新计算类调整别处的 support,也不会影响本类已验算通过的流程。
///
private sealed class LocalCalculationSupport : IPPCCalculationSupport
{
private static readonly object _refpropLock = new object();
private static volatile bool _rpInitialized;
public 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;
long hfmixLen = hfmix.Length;
long hrfLen = hrf.Length;
long 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;
return true;
}
}
catch (Exception ex)
{
error = $"REFPROP 初始化异常: {ex.Message}";
_rpInitialized = false;
return false;
}
}
public bool TrySATP_SaturationByP_MPa(double pressureMPa, out double tSatK, out double Dl_molL, out double Dv_molL, out string error) => throw new NotSupportedException();
public bool TryTPRHO_VaporDensity_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 = 2;
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;
}
public bool TryTHERM_VaporEntropy_ByTD(double temperatureC, double densityMolPerL, out double entropy_kJ_per_kgK, out string error)
{
entropy_kJ_per_kgK = 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;
double e = 0;
double hJmol = 0;
double sJmolK = 0;
double cv = 0;
double cp = 0;
double w = 0;
double 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);
}
entropy_kJ_per_kgK = (sJmolK / molarMassKgPerMol) * 0.001;
return true;
}
public 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;
}
public 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;
double e = 0;
double hJmol = 0;
double sJmolK = 0;
double cv = 0;
double cp = 0;
double w = 0;
double 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;
}
public bool TryTHERM_Enthalpy_kJkg_ByT_K_D(double temperatureK, double densityMolPerL, out double h_kJ_per_kg, out string error)
{
h_kJ_per_kg = double.NaN;
error = string.Empty;
double tK = temperatureK;
double D = densityMolPerL;
double[] x = new double[20];
x[0] = 1.0;
double pOut = 0;
double e = 0;
double hJmol = 0;
double sJmolK = 0;
double cv = 0;
double cp = 0;
double w = 0;
double 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_kJ_per_kg = (hJmol / molarMassKgPerMol) * 0.001;
return true;
}
public 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;
}
public bool TryGetIsentropicOutletEnthalpy_h2s_ByP2AndS1_BarA(double dischargePressureBarA, double suctionEntropy_kJkgK, out double h2s_kJkg, out string error)
{
h2s_kJkg = double.NaN;
error = string.Empty;
double pKPa = dischargePressureBarA * 100.0;
if (pKPa <= 0)
{
error = $"无效排气压力: {dischargePressureBarA} BarA";
return false;
}
if (double.IsNaN(suctionEntropy_kJkgK) || double.IsInfinity(suctionEntropy_kJkgK))
{
error = "无效吸气熵 s1";
return false;
}
if (!TryConvertS_kJkgK_To_JmolK(suctionEntropy_kJkgK, out var s_JmolK, out var convErr))
{
error = convErr;
return false;
}
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;
}
return TryConvertH_Jmol_To_kJkg(h, out h2s_kJkg, out error);
}
private static double GetMolarMass()
{
double wmm = 0;
double Trp = 0;
double Tnbpt = 0;
double Tc = 0;
double Pc = 0;
double Dc = 0;
double Zc = 0;
double acf = 0;
double dip = 0;
double 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 static 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 static bool TryConvertS_kJkgK_To_JmolK(double s_kJkgK, out double s_JmolK, out string error)
{
s_JmolK = double.NaN;
error = string.Empty;
double molarMassKgPerMol = GetMolarMass();
if (molarMassKgPerMol <= 0)
{
error = "无效的摩尔质量";
return false;
}
s_JmolK = s_kJkgK * 1000.0 * molarMassKgPerMol;
return true;
}
}
}
}