| 57 | |
| 58 | |
| 59 | def plot_fluid(fluid: str, csv_path: str) -> dict: |
| 60 | data = load_csv(csv_path) |
| 61 | p = data["p"] |
| 62 | h = data["h"] |
| 63 | rel = np.maximum(data["rel_err"], 1e-12) * 100.0 # percent, with floor |
| 64 | |
| 65 | max_pct = float(rel.max()) |
| 66 | p99 = float(np.percentile(rel, 99)) |
| 67 | p50 = float(np.percentile(rel, 50)) |
| 68 | |
| 69 | # Saturation curve for context. Skip cleanly if CoolProp isn't |
| 70 | # importable or if the fluid is unknown to PropsSI -- the plot is |
| 71 | # still useful without the dome overlay. |
| 72 | psat = None |
| 73 | hLs = None |
| 74 | hVs = None |
| 75 | if CP is not None: |
| 76 | try: |
| 77 | Tt = CP.PropsSI("Ttriple", fluid) |
| 78 | Tc = CP.PropsSI("Tcrit", fluid) |
| 79 | Tsat = np.linspace(Tt + 0.1, Tc - 0.01, 400) |
| 80 | psat = CP.PropsSI("P", "T", Tsat, "Q", 0, fluid) |
| 81 | hLs = CP.PropsSI("Hmass", "T", Tsat, "Q", 0, fluid) |
| 82 | hVs = CP.PropsSI("Hmass", "T", Tsat, "Q", 1, fluid) |
| 83 | except Exception: |
| 84 | psat = None |
| 85 | hLs = None |
| 86 | hVs = None |
| 87 | |
| 88 | fig, ax = plt.subplots(1, 1, figsize=(8, 7)) |
| 89 | cnorm = colors.LogNorm(vmin=1e-10, vmax=10) |
| 90 | ax.scatter(h / 1e3, p, c=rel, s=4, cmap="jet", norm=cnorm, edgecolors="none") |
| 91 | if psat is not None: |
| 92 | ax.plot(hLs / 1e3, psat, "k-", lw=1.0, alpha=0.8) |
| 93 | ax.plot(hVs / 1e3, psat, "k-", lw=1.0, alpha=0.8) |
| 94 | ax.set_yscale("log") |
| 95 | ax.set_xlabel("h [kJ/kg]") |
| 96 | ax.set_ylabel("p [Pa]") |
| 97 | ax.set_title( |
| 98 | f"{fluid} HmassP ρ rel error: SVDSBTL e2e (C++ port)\n" |
| 99 | f"N={len(rel)} med={p50:.1e} p99={p99:.1e} max={max_pct:.1e} %" |
| 100 | ) |
| 101 | plt.colorbar( |
| 102 | plt.cm.ScalarMappable(norm=cnorm, cmap="jet"), |
| 103 | ax=ax, |
| 104 | label=r"$|\rho_{\rm pred}/\rho_{\rm EOS} - 1| \times 100\,[\%]$", |
| 105 | shrink=0.85, |
| 106 | ) |
| 107 | plt.tight_layout() |
| 108 | png_path = csv_path.replace(".csv", ".png") |
| 109 | fig.savefig(png_path, dpi=110, bbox_inches="tight") |
| 110 | plt.close(fig) |
| 111 | return { |
| 112 | "fluid": fluid, |
| 113 | "n": int(len(rel)), |
| 114 | "max_pct": max_pct, |
| 115 | "p99_pct": p99, |
| 116 | "p50_pct": p50, |