645 lines
22 KiB
C#
645 lines
22 KiB
C#
using CapMachine.Core;
|
||
using System;
|
||
|
||
namespace CapMachine.Wpf.PPCalculation
|
||
{
|
||
/// <summary>
|
||
/// 干度(品质)计算器:按“焓加权混合 + 饱和焓归一化”的流程计算 Dryness1/Dryness2。
|
||
/// </summary>
|
||
public sealed class EnthalpyDrynessCalculator
|
||
{
|
||
private readonly object _refpropLock;
|
||
|
||
private static volatile bool _rpInitialized;
|
||
|
||
/// <summary>
|
||
/// 构造函数。
|
||
/// </summary>
|
||
/// <param name="refpropLock">REFPROP 全局互斥锁对象(必须与系统其它 REFPROP 调用共用,以避免并发竞态)。</param>
|
||
public EnthalpyDrynessCalculator(object refpropLock)
|
||
{
|
||
_refpropLock = refpropLock ?? throw new ArgumentNullException(nameof(refpropLock));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 干度计算输入模型(以 Tag 读数为准)。
|
||
/// </summary>
|
||
public readonly struct Input
|
||
{
|
||
public Input(
|
||
double gasPreValvePressBarA,
|
||
double gasPreValveTempC,
|
||
double txvFrPressBarA,
|
||
double txvFrTempC,
|
||
double inhPressBarA,
|
||
double vrvFlowKgPerH,
|
||
double liqRefFlowKgPerH,
|
||
double lubeFlowKgPerH)
|
||
{
|
||
GasPreValvePressBarA = gasPreValvePressBarA;
|
||
GasPreValveTempC = gasPreValveTempC;
|
||
TxvFrPressBarA = txvFrPressBarA;
|
||
TxvFrTempC = txvFrTempC;
|
||
InhPressBarA = inhPressBarA;
|
||
VRVFlowKgPerH = vrvFlowKgPerH;
|
||
LiqRefFlowKgPerH = liqRefFlowKgPerH;
|
||
LubeFlowKgPerH = lubeFlowKgPerH;
|
||
}
|
||
|
||
public double GasPreValvePressBarA { get; }
|
||
public double GasPreValveTempC { get; }
|
||
public double TxvFrPressBarA { get; }
|
||
public double TxvFrTempC { get; }
|
||
public double InhPressBarA { get; }
|
||
|
||
public double VRVFlowKgPerH { get; }
|
||
public double LiqRefFlowKgPerH { get; }
|
||
public double LubeFlowKgPerH { get; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 干度计算输出模型。
|
||
/// </summary>
|
||
public readonly struct Result
|
||
{
|
||
public Result(
|
||
double gasFlowKgPerH,
|
||
double gasEnthalpy_kJkg,
|
||
double liquidEnthalpy_kJkg,
|
||
double satLiquidEnthalpy_kJkg,
|
||
double satVaporEnthalpy_kJkg,
|
||
bool isDryness1Success,
|
||
double dryness1_01,
|
||
double hMix1_kJkg,
|
||
string error1,
|
||
bool isDryness2Success,
|
||
double dryness2_01,
|
||
double hMix2_kJkg,
|
||
string error2)
|
||
{
|
||
GasFlowKgPerH = gasFlowKgPerH;
|
||
GasEnthalpy_kJkg = gasEnthalpy_kJkg;
|
||
LiquidEnthalpy_kJkg = liquidEnthalpy_kJkg;
|
||
SatLiquidEnthalpy_kJkg = satLiquidEnthalpy_kJkg;
|
||
SatVaporEnthalpy_kJkg = satVaporEnthalpy_kJkg;
|
||
|
||
IsDryness1Success = isDryness1Success;
|
||
Dryness1_01 = dryness1_01;
|
||
HMix1_kJkg = hMix1_kJkg;
|
||
Error1 = error1 ?? string.Empty;
|
||
|
||
IsDryness2Success = isDryness2Success;
|
||
Dryness2_01 = dryness2_01;
|
||
HMix2_kJkg = hMix2_kJkg;
|
||
Error2 = error2 ?? string.Empty;
|
||
}
|
||
|
||
public double GasFlowKgPerH { get; }
|
||
public double GasEnthalpy_kJkg { get; }
|
||
public double LiquidEnthalpy_kJkg { get; }
|
||
public double SatLiquidEnthalpy_kJkg { get; }
|
||
public double SatVaporEnthalpy_kJkg { get; }
|
||
|
||
public bool IsDryness1Success { get; }
|
||
public double Dryness1_01 { get; }
|
||
public double HMix1_kJkg { get; }
|
||
public string Error1 { get; }
|
||
|
||
public bool IsDryness2Success { get; }
|
||
public double Dryness2_01 { get; }
|
||
public double HMix2_kJkg { get; }
|
||
public string Error2 { get; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算干度 1/2。
|
||
/// </summary>
|
||
/// <param name="input">输入数据。</param>
|
||
/// <returns>计算结果(包含两路干度及中间量)。</returns>
|
||
public Result Calculate(Input input)
|
||
{
|
||
if (!EnsureRefpropInitialized(out _))
|
||
{
|
||
return new Result(
|
||
gasFlowKgPerH: double.NaN,
|
||
gasEnthalpy_kJkg: double.NaN,
|
||
liquidEnthalpy_kJkg: double.NaN,
|
||
satLiquidEnthalpy_kJkg: double.NaN,
|
||
satVaporEnthalpy_kJkg: double.NaN,
|
||
isDryness1Success: false,
|
||
dryness1_01: double.NaN,
|
||
hMix1_kJkg: double.NaN,
|
||
error1: "REFPROP 未初始化",
|
||
isDryness2Success: false,
|
||
dryness2_01: double.NaN,
|
||
hMix2_kJkg: double.NaN,
|
||
error2: "REFPROP 未初始化");
|
||
}
|
||
|
||
double gasFlowKgPerH = input.VRVFlowKgPerH - input.LiqRefFlowKgPerH;
|
||
|
||
double gas_hVap_kJkg = 0.0;
|
||
if (TryTPRHO_VaporDensity_ByTP_MPa_C(input.GasPreValvePressBarA * 0.1, input.GasPreValveTempC, out var dVap_molL, out _))
|
||
{
|
||
if (TryTHERM_VaporEnthalpy_ByTD(input.GasPreValveTempC, dVap_molL, out var hVap_kJkg, out _))
|
||
{
|
||
gas_hVap_kJkg = hVap_kJkg;
|
||
}
|
||
}
|
||
|
||
double liquid_hLiq_kJkg = 0.0;
|
||
if (TryTPRHO_LiquidDensity_ByTP_MPa_C(input.TxvFrPressBarA * 0.1, input.TxvFrTempC, out var dLiq_molL, out _))
|
||
{
|
||
if (TryTHERM_LiquidEnthalpy_ByTD(input.TxvFrTempC, dLiq_molL, out var hLiq_kJkg, out _))
|
||
{
|
||
liquid_hLiq_kJkg = hLiq_kJkg;
|
||
}
|
||
}
|
||
|
||
double hSatL_kJkg = 0.0;
|
||
double hSatV_kJkg = 0.0;
|
||
if (TryGetSaturationLiquidEnthalpy_ByP_MPa(input.InhPressBarA * 0.1, out var satL, out _) &&
|
||
TryGetSaturationVaporEnthalpy_ByP_MPa(input.InhPressBarA * 0.1, out var satV, out _))
|
||
{
|
||
hSatL_kJkg = satL;
|
||
hSatV_kJkg = satV;
|
||
}
|
||
|
||
bool ok1 = TryComputeDrynessByEnthalpy(
|
||
gas_hVap_kJkg,
|
||
liquid_hLiq_kJkg,
|
||
gasFlowKgPerH,
|
||
input.LiqRefFlowKgPerH,
|
||
hSatL_kJkg,
|
||
hSatV_kJkg,
|
||
out var dryness1,
|
||
out var hMix1,
|
||
out var err1);
|
||
|
||
bool ok2 = TryComputeDrynessByEnthalpy2(
|
||
gas_hVap_kJkg,
|
||
liquid_hLiq_kJkg,
|
||
gasFlowKgPerH,
|
||
input.LubeFlowKgPerH,
|
||
input.LiqRefFlowKgPerH,
|
||
hSatL_kJkg,
|
||
hSatV_kJkg,
|
||
out var dryness2,
|
||
out var hMix2,
|
||
out var err2);
|
||
|
||
return new Result(
|
||
gasFlowKgPerH: gasFlowKgPerH,
|
||
gasEnthalpy_kJkg: gas_hVap_kJkg,
|
||
liquidEnthalpy_kJkg: liquid_hLiq_kJkg,
|
||
satLiquidEnthalpy_kJkg: hSatL_kJkg,
|
||
satVaporEnthalpy_kJkg: hSatV_kJkg,
|
||
isDryness1Success: ok1,
|
||
dryness1_01: dryness1,
|
||
hMix1_kJkg: hMix1,
|
||
error1: err1,
|
||
isDryness2Success: ok2,
|
||
dryness2_01: dryness2,
|
||
hMix2_kJkg: hMix2,
|
||
error2: err2);
|
||
}
|
||
|
||
/// <summary>
|
||
/// REFPROP 初始化(幂等)。
|
||
/// </summary>
|
||
/// <param name="error">失败原因。</param>
|
||
/// <returns>是否初始化成功。</returns>
|
||
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;
|
||
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;
|
||
}
|
||
}
|
||
|
||
private 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;
|
||
}
|
||
|
||
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_VaporEnthalpy_ByTD(double temperatureC, double densityMolPerL, out double h_vap_kJ_per_kg, out string error)
|
||
{
|
||
h_vap_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;
|
||
|
||
if (!TryGetMolarMassKgPerMol(1, out var molarMassKgPerMol, out 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_vap_kJ_per_kg = (hJmol / molarMassKgPerMol) * 0.001;
|
||
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;
|
||
|
||
if (!TryGetMolarMassKgPerMol(1, out var molarMassKgPerMol, out 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_SaturationByP_MPa(double pressureMPa, out double tSatK, out double Dl_molL, out double Dv_molL, out string error)
|
||
{
|
||
tSatK = double.NaN;
|
||
Dl_molL = double.NaN;
|
||
Dv_molL = double.NaN;
|
||
error = string.Empty;
|
||
|
||
double pKPa = pressureMPa * 1000.0;
|
||
double[] x = new double[20];
|
||
x[0] = 1.0;
|
||
|
||
long kph = 1;
|
||
double Dl = 0, Dv = 0;
|
||
double[] xliq = new double[20];
|
||
double[] xvap = new double[20];
|
||
long ierr = 0, herrLen = 255;
|
||
string herr = new string(' ', 255);
|
||
|
||
lock (_refpropLock)
|
||
{
|
||
IRefProp64.SATPdll(ref pKPa, x, ref kph, ref tSatK, ref Dl, ref Dv, xliq, xvap, ref ierr, ref herr, ref herrLen);
|
||
}
|
||
|
||
if (ierr != 0)
|
||
{
|
||
error = $"SATP 错误: {herr.Trim()} (ierr={ierr})";
|
||
return false;
|
||
}
|
||
|
||
Dl_molL = Dl;
|
||
Dv_molL = Dv;
|
||
return true;
|
||
}
|
||
|
||
private 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, e = 0, hJmol = 0, sJmolK = 0, cv = 0, cp = 0, w = 0, hjt = 0;
|
||
|
||
if (!TryGetMolarMassKgPerMol(1, out var molarMassKgPerMol, out 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;
|
||
}
|
||
|
||
private bool TryGetSaturationLiquidEnthalpy_ByP_MPa(double pressureMPa, out double h_liq_kJkg, out string error)
|
||
{
|
||
h_liq_kJkg = double.NaN;
|
||
error = string.Empty;
|
||
|
||
if (!TrySATP_SaturationByP_MPa(pressureMPa, out double tSatK, out double Dl, out _, out error))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
return TryTHERM_Enthalpy_kJkg_ByT_K_D(tSatK, Dl, out h_liq_kJkg, out error);
|
||
}
|
||
|
||
private bool TryGetSaturationVaporEnthalpy_ByP_MPa(double pressureMPa, out double h_vap_kJkg, out string error)
|
||
{
|
||
h_vap_kJkg = double.NaN;
|
||
error = string.Empty;
|
||
|
||
if (!TrySATP_SaturationByP_MPa(pressureMPa, out double tSatK, out _, out double Dv, out error))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
return TryTHERM_Enthalpy_kJkg_ByT_K_D(tSatK, Dv, out h_vap_kJkg, out error);
|
||
}
|
||
|
||
private static bool TryComputeDrynessByEnthalpy(
|
||
double hVap_kJkg,
|
||
double hLiq_kJkg,
|
||
double mGas_kg_h,
|
||
double mLiq_kg_h,
|
||
double hSatL_kJkg,
|
||
double hSatV_kJkg,
|
||
out double dryness,
|
||
out double hMix_kJkg,
|
||
out string error)
|
||
{
|
||
dryness = double.NaN;
|
||
hMix_kJkg = double.NaN;
|
||
error = string.Empty;
|
||
|
||
if (double.IsNaN(hVap_kJkg) || double.IsNaN(hLiq_kJkg) || double.IsNaN(hSatL_kJkg) || double.IsNaN(hSatV_kJkg))
|
||
{
|
||
error = "输入焓值存在 NaN";
|
||
return false;
|
||
}
|
||
if (double.IsNaN(mGas_kg_h) || double.IsNaN(mLiq_kg_h))
|
||
{
|
||
error = "输入质量流量存在 NaN";
|
||
return false;
|
||
}
|
||
|
||
double mg = Math.Max(0.0, mGas_kg_h);
|
||
double ml = Math.Max(0.0, mLiq_kg_h);
|
||
double mSum = mg + ml;
|
||
if (mSum <= 0)
|
||
{
|
||
error = "气液质量流量之和为 0,无法进行加权混合焓计算";
|
||
return false;
|
||
}
|
||
|
||
hMix_kJkg = (hVap_kJkg * mg + hLiq_kJkg * ml) / mSum;
|
||
|
||
double denom = (hSatV_kJkg - hSatL_kJkg);
|
||
const double eps = 1e-9;
|
||
if (Math.Abs(denom) < eps)
|
||
{
|
||
error = "饱和气/液焓差过小,无法计算干度(可能接近临界点或输入异常)";
|
||
return false;
|
||
}
|
||
|
||
double x = (hMix_kJkg - hSatL_kJkg) / denom;
|
||
|
||
if (double.IsNaN(x) || double.IsInfinity(x))
|
||
{
|
||
error = "干度计算结果异常(NaN/Inf)";
|
||
return false;
|
||
}
|
||
|
||
dryness = Math.Min(1.0, Math.Max(0.0, x));
|
||
return true;
|
||
}
|
||
|
||
private static bool TryComputeDrynessByEnthalpy2(
|
||
double hVap_kJkg,
|
||
double hLiq_kJkg,
|
||
double mGas_kg_h,
|
||
double lubeFlow_kg_h,
|
||
double mLiq_kg_h,
|
||
double hSatL_kJkg,
|
||
double hSatV_kJkg,
|
||
out double dryness,
|
||
out double hMix_kJkg,
|
||
out string error)
|
||
{
|
||
dryness = double.NaN;
|
||
hMix_kJkg = double.NaN;
|
||
error = string.Empty;
|
||
|
||
if (double.IsNaN(hVap_kJkg) || double.IsNaN(hLiq_kJkg) || double.IsNaN(hSatL_kJkg) || double.IsNaN(hSatV_kJkg))
|
||
{
|
||
error = "输入焓值存在 NaN";
|
||
return false;
|
||
}
|
||
if (double.IsNaN(mGas_kg_h) || double.IsNaN(mLiq_kg_h))
|
||
{
|
||
error = "输入质量流量存在 NaN";
|
||
return false;
|
||
}
|
||
|
||
double mg = Math.Max(0.0, mGas_kg_h) + Math.Max(0.0, lubeFlow_kg_h);
|
||
double ml = Math.Max(0.0, mLiq_kg_h);
|
||
double mSum = mg + ml;
|
||
if (mSum <= 0)
|
||
{
|
||
error = "气液质量流量之和为 0,无法进行加权混合焓计算";
|
||
return false;
|
||
}
|
||
|
||
hMix_kJkg = (hVap_kJkg * mg + hLiq_kJkg * ml) / mSum;
|
||
|
||
double denom = (hSatV_kJkg - hSatL_kJkg);
|
||
const double eps = 1e-9;
|
||
if (Math.Abs(denom) < eps)
|
||
{
|
||
error = "饱和气/液焓差过小,无法计算干度(可能接近临界点或输入异常)";
|
||
return false;
|
||
}
|
||
|
||
double x = (hMix_kJkg - hSatL_kJkg) / denom;
|
||
|
||
if (double.IsNaN(x) || double.IsInfinity(x))
|
||
{
|
||
error = "干度计算结果异常(NaN/Inf)";
|
||
return false;
|
||
}
|
||
|
||
dryness = Math.Min(1.0, Math.Max(0.0, x));
|
||
return true;
|
||
}
|
||
|
||
private bool TryGetMolarMassKgPerMol(long componentId, out double molarMassKgPerMol, out string error)
|
||
{
|
||
molarMassKgPerMol = double.NaN;
|
||
error = string.Empty;
|
||
|
||
try
|
||
{
|
||
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;
|
||
|
||
lock (_refpropLock)
|
||
{
|
||
IRefProp64.INFOdll(ref componentId, ref wmm, ref Trp, ref Tnbpt, ref Tc, ref Pc, ref Dc, ref Zc, ref acf, ref dip, ref Rgas);
|
||
}
|
||
molarMassKgPerMol = wmm * 0.001;
|
||
if (molarMassKgPerMol <= 0)
|
||
{
|
||
error = "无效的摩尔质量";
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
error = $"读取摩尔质量异常: {ex.Message}";
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
}
|