File size: 3,467 Bytes
e85a399
60943f3
603b5b4
60943f3
 
 
603b5b4
 
 
 
 
 
 
60943f3
e85a399
60943f3
 
e85a399
 
60943f3
e85a399
 
 
 
 
 
60943f3
 
 
e85a399
60943f3
e85a399
 
 
 
 
 
60943f3
 
 
e85a399
60943f3
e85a399
 
 
60943f3
e85a399
 
 
60943f3
 
 
 
 
 
 
603b5b4
 
 
 
 
 
60943f3
 
 
 
 
e85a399
 
60943f3
 
e85a399
 
 
 
 
 
 
 
 
 
 
60943f3
 
 
 
 
 
 
 
 
 
603b5b4
60943f3
 
e85a399
60943f3
 
 
 
 
e85a399
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import { useCallback, useEffect, useRef, useState } from "react";
import PyodideWorker from "./pyodide.worker.ts?worker";
import type { ComparisonTrajectory, PlotData, Settings, WorkerMessage } from "./types.ts";


export default function usePyodide(initialSettings: Settings) {
  const [comparison, setComparison] = useState<ComparisonTrajectory[]>([]);
  const [comparisonBusy, setComparisonBusy] = useState(false);
  const comparisonRequest = useRef(0);
  const compare = useCallback((settings: Settings[], ids: number[], iteration: number) => {
    setComparisonBusy(true);
    workerRef.current?.postMessage({ type: "COMPARE", requestId: ++comparisonRequest.current, settings, ids, iteration });
  }, []);
  const [plotData, setPlotData] = useState<PlotData>({});
  const [currentIteration, setCurrentIteration] = useState(0);
  const [isLoading, setIsLoading] = useState<boolean>(true);
  const workerRef = useRef<Worker | null>(null);
  const plotDataRef = useRef<PlotData>({});
  const currentIterationRef = useRef(0);

  function selectIteration(iteration: number) {
    currentIterationRef.current = iteration;
    setCurrentIteration(iteration);
  }

  const sendInit = useCallback((settings: Settings) => {
    if (workerRef.current) {
      workerRef.current.postMessage({ type: "INIT", settings });
    }
  }, []);

  const sendNextStep = useCallback(() => {
    const lastPlottedIteration = Math.max((plotDataRef.current.trajectoryValues?.x.length ?? 1) - 1, 0);
    if (currentIterationRef.current < lastPlottedIteration) {
      selectIteration(currentIterationRef.current + 1);
      return;
    }
    if (workerRef.current) {
      workerRef.current.postMessage({ type: "NEXT_STEP" });
    }
  }, []);

  const sendPrevStep = useCallback(() => {
    selectIteration(Math.max(currentIterationRef.current - 1, 0));
  }, []);

  const sendReset = useCallback(() => {
    selectIteration(0);
  }, []);

  useEffect(() => {
    const worker = new PyodideWorker();
    workerRef.current = worker;

    worker.onmessage = (event) => {
      const message = event.data as WorkerMessage;
      if (message.type === "COMPARISON_RESULT") {
        if (message.requestId === comparisonRequest.current) {
          setComparison(message.trajectories);
          setComparisonBusy(false);
        }
      } else if (message.type === "READY") {
        console.log("Pyodide is ready");
        setIsLoading(false);
        sendInit(initialSettings);
      } else if (message.type === "RESULT") {
        // todo data validation / type
        setPlotData((prevData) => {
          const nextData = {
          functionValues: message.data.functionValues || prevData.functionValues,
          trajectoryValues: message.data.trajectoryValues || prevData.trajectoryValues,
          };
          plotDataRef.current = nextData;

          if (message.data.trajectoryValues) {
            const lastIteration = Math.max(message.data.trajectoryValues.x.length - 1, 0);
            if (lastIteration <= 0 || lastIteration > currentIterationRef.current) {
              selectIteration(lastIteration);
            }
          }
          return nextData;
        });
      }
    };

    return () => {
      worker.terminate();
    };

  }, []);

  return {
    comparison, comparisonBusy, compare,
    isLoading,
    plotData,
    currentIteration,
    sendInit: sendInit,
    sendReset: sendReset,
    sendNextStep: sendNextStep,
    sendPrevStep: sendPrevStep,
  }
}