-- Executable smoke test for the public LuaCoolProp API documented in the -- developer reference. Run through scripts/build-examples.sh so the same -- external CoolProp library is used by Lua and all three TeX formats. local lcp = require("luacoolprop") local _, loaded_from = lcp.load_library() assert(type(loaded_from) == "string", "CoolProp loader name must be a string") assert(type(lcp.version()) == "string", "CoolProp version must be a string") assert(type(lcp.gitrevision()) == "string", "CoolProp revision must be a string") assert(type(lcp.fluid_param_string("R134a", "aliases")) == "string", "fluid aliases must be a string") assert(type(lcp.parameter_information_string("Hmass")) == "string", "parameter information must be a string") local h = lcp.propsSI("Hmass", "P", 2.5e5, "Q", 1, "R134a") assert(type(h) == "number", "propsSI must return a number") -- Keep a single deterministic cleanup point around the native handle. The -- finalizer is a fallback, not the normal resource-management mechanism. local state local ok, result = xpcall(function() state = lcp.AbstractState("HEOS", "R134a") state:update("PT_INPUTS", 3e5, 293.15) return state:keyed_output("Hmass") end, debug.traceback) if state ~= nil then state:free() state:free() -- The documented cleanup operation is idempotent. state = nil end if not ok then error(result, 0) end assert(type(result) == "number", "AbstractState output must be a number") local ph = lcp.diagram.get_type("PH") local curve_options = { fluid = "R134a", pressure_min = 1e5, pressure_max = 2e6, enthalpy_scale = 1e-3, pressure_scale = 1e-5, } local isotherm_points = ph.isotherm_curve(curve_options, 293.15) assert(#isotherm_points >= 2, "isotherm must contain at least two points") local quality_points = ph.quality_curve(curve_options, 0.5) assert(#quality_points >= 2, "quality curve must contain at least two points") local plot_code = ph.plots({ fluid = "R134a", quality = true, isotherm = true, quality_values = "0,0.5,1", temperature_values = "-20,0,20", temperature_unit = "celsius", labels = true, }) assert(plot_code:find("\\addplot", 1, true), "PH plot renderer must emit PGFPlots commands") local process_points, metadata = ph.process_points({ fluid = "R134a", type = "isentropic", from = "pressure=2bar,quality=1", to = "pressure=10bar", }) assert(#process_points >= 2, "process must contain at least two points") assert(metadata.kind == "isentropic", "process kind must be normalized") assert(type(metadata.to.h) == "number", "completed endpoint must contain enthalpy") local pv = lcp.diagram.get_type("PV") local pv_options = { fluid = "R134a", pressure_min = 1e5, pressure_max = 2e6, specific_volume_scale = 1, pressure_scale = 1e-5, } local pv_isotherm = pv.isotherm_curve(pv_options, 293.15) assert(#pv_isotherm >= 2 and pv_isotherm[1].x > 0, "PV isotherm must contain positive log-axis points") local pv_code = pv.plots({ fluid = "R134a", quality = true, isotherm = true, quality_values = "0,0.5,1", temperature_values = "0,20", }) assert(pv_code:find("name path=lcp-pv", 1, true), "PV renderer must emit diagram-specific named paths") local pv_process, pv_metadata = pv.process_points({ fluid = "R134a", type = "isentropic", from = "pressure=2bar,quality=1", to = "pressure=10bar", }) assert(#pv_process >= 2 and pv_metadata.to.x == pv_metadata.to.v, "PV process coordinates must expose scaled specific volume") local ts = lcp.diagram.get_type("TS") local ts_options = { fluid = "R134a", pressure_min = 1e5, pressure_max = 2e6, entropy_scale = 1e-3, temperature_scale = 1, } local ts_isenthalp = ts.isenthalp_curve(ts_options, 300e3) assert(#ts_isenthalp >= 2 and ts_isenthalp[1].x == ts_isenthalp[1].s * 1e-3 and ts_isenthalp[1].y == ts_isenthalp[1].T, "TS isenthalp must expose scaled entropy and temperature") local ts_code = ts.plots({ fluid = "R134a", quality = true, isenthalp = true, quality_values = "0,0.5,1", enthalpy_values = "250,300,350", }) assert(ts_code:find("name path=lcp-ts", 1, true), "TS renderer must emit diagram-specific named paths") local ts_process, ts_metadata = ts.process_points({ fluid = "R134a", type = "isentropic", from = "pressure=2bar,quality=1", to = "pressure=10bar", }) assert(#ts_process == 2 and ts_metadata.from.x == ts_metadata.to.x, "TS isentropic process must be an exact vertical segment") local hs = lcp.diagram.get_type("HS") local hs_options = { fluid = "Water", pressure_min = 1e4, pressure_max = 3e7, entropy_scale = 1e-3, enthalpy_scale = 1e-3, temperature_unit = "celsius", isobar_temperature_min = 10, isobar_temperature_max = 500, } local hs_isobar = hs.isobar_curve(hs_options, 1e5) assert(#hs_isobar >= 2 and hs_isobar[1].x == hs_isobar[1].s * 1e-3 and hs_isobar[1].y == hs_isobar[1].h * 1e-3, "HS isobar must expose scaled entropy and enthalpy") local hs_code = hs.plots({ fluid = "Water", quality = true, isochore = true, isotherm = true, isobar = true, quality_values = "0,0.5,1", specific_volume_values = "0.01,0.1,1", temperature_values = "100,200,300", isobar_values = "0.1,1,10", }) for _, family in ipairs({"q", "v", "T", "p"}) do assert(hs_code:find("name path=lcp-hs-" .. family, 1, true), "HS renderer must emit the " .. family .. " family") end local hs_process, hs_metadata = hs.process_points({ fluid = "Water", type = "isentropic", from = "pressure=1bar,quality=1", to = "pressure=10bar", }) assert(#hs_process == 2 and hs_metadata.from.x == hs_metadata.to.x, "HS isentropic process must be an exact vertical segment") local pt = lcp.diagram.get_type("PT") local pt_constants = lcp.fluid_constants("R134a") local pt_options = { fluid = "R134a", pressure_min = pt_constants.ptriple, pressure_max = pt_constants.pcrit * 1.1, temperature_axis_unit = "celsius", pressure_axis_unit = "bar", } local phase_envelope = pt.phase_envelope_curve(pt_options) assert(#phase_envelope >= 3 and phase_envelope[1].triple and phase_envelope[#phase_envelope].critical, "PT phase envelope must join the exact triple and critical points") local pt_code = pt.plots({ fluid = "R134a", phase_envelope = true, isentrope = true, isenthalp = true, isochore = true, entropy_values = "1.4,1.7,2.0", enthalpy_values = "200,300,400", specific_volume_values = "0.001,0.01,0.1", }) for _, family in ipairs({"phase-envelope", "s", "h", "v"}) do assert(pt_code:find("name path=lcp-pt-" .. family, 1, true), "PT renderer must emit the " .. family .. " family") end local pt_process, pt_metadata = pt.process_points({ fluid = "R134a", type = "isentropic", from = "pressure=2bar,quality=1", to = "pressure=10bar", }) assert(#pt_process >= 2 and pt_metadata.diagram_type == "PT", "PT process must use the shared process API") io.write("Lua API smoke test passed\n")