| 29 | type StepMode = "n_points" | "step"; |
| 30 | |
| 31 | export default function SatSetupDialog({ fluids, basis, initial, onConfirm, onCancel }: Props) { |
| 32 | const [fluid, setFluid] = useState(initial?.fluid ?? "Water"); |
| 33 | const [byTemp, setByTemp] = useState(initial?.byTemp ?? true); |
| 34 | const [minVal, setMinVal] = useState(String(initial?.minVal ?? "")); |
| 35 | const [maxVal, setMaxVal] = useState(String(initial?.maxVal ?? "")); |
| 36 | const [stepMode, setStepMode] = useState<StepMode>("n_points"); |
| 37 | const [nPoints, setNPoints] = useState(String(initial?.nPoints ?? 20)); |
| 38 | const [stepSize, setStepSize] = useState(""); |
| 39 | const [limitsError, setLimitsError] = useState<string | null>(null); |
| 40 | |
| 41 | // Auto-populate min/max from EOS limits when fluid or axis changes |
| 42 | useEffect(() => { |
| 43 | if (!fluid) return; |
| 44 | setLimitsError(null); |
| 45 | invoke<FluidLimits>("get_fluid_limits", { fluid }) |
| 46 | .then((lim) => { |
| 47 | if (byTemp) { |
| 48 | setMinVal(lim.t_min.toFixed(2)); |
| 49 | setMaxVal(lim.t_max.toFixed(2)); |
| 50 | setStepSize("5"); |
| 51 | } else { |
| 52 | setMinVal(lim.p_min.toExponential(3)); |
| 53 | setMaxVal(lim.p_max.toExponential(3)); |
| 54 | setStepSize(((lim.p_max - lim.p_min) / 50).toExponential(2)); |
| 55 | } |
| 56 | }) |
| 57 | .catch((e) => setLimitsError(String(e))); |
| 58 | }, [fluid, byTemp]); |
| 59 | |
| 60 | const handleConfirm = () => { |
| 61 | const min = parseFloat(minVal); |
| 62 | const max = parseFloat(maxVal); |
| 63 | if (isNaN(min) || isNaN(max) || max <= min) return; |
| 64 | |
| 65 | let n: number; |
| 66 | if (stepMode === "n_points") { |
| 67 | n = parseInt(nPoints, 10); |
| 68 | } else { |
| 69 | const step = parseFloat(stepSize); |
| 70 | if (isNaN(step) || step <= 0) return; |
| 71 | // n cells of width `step` → n+1 points; bias toward "include endpoints" |
| 72 | n = Math.max(2, Math.min(50000, Math.round((max - min) / step) + 1)); |
| 73 | } |
| 74 | if (isNaN(n) || n < 2) return; |
| 75 | |
| 76 | onConfirm({ fluid, backend: "HEOS", byTemp, minVal: min, maxVal: max, nPoints: n }); |
| 77 | }; |
| 78 | |
| 79 | const label = byTemp ? "T (K)" : "P (Pa)"; |
| 80 | const stepUnit = byTemp ? "K" : "Pa"; |
| 81 | |
| 82 | const previewN = (() => { |
| 83 | if (stepMode === "n_points") return null; |
| 84 | const min = parseFloat(minVal), max = parseFloat(maxVal), step = parseFloat(stepSize); |
| 85 | if (!isFinite(min) || !isFinite(max) || !isFinite(step) || step <= 0 || max <= min) return null; |
| 86 | return Math.max(2, Math.min(50000, Math.round((max - min) / step) + 1)); |
| 87 | })(); |
| 88 | |