diff --git a/src/FEAWorkerScript.js b/src/FEAWorkerScript.js new file mode 100644 index 0000000..a50deab --- /dev/null +++ b/src/FEAWorkerScript.js @@ -0,0 +1,118 @@ +import * as Comlink from "https://unpkg.com/comlink/dist/esm/comlink.mjs"; +import { basicLog } from "./utilities/utilitiesScript.js"; + +export class FEAWorkerScript { + constructor() { + this.worker = null; + this.feaWorker = null; + this.isReady = false; + + this._initWorker(); + } + + async _initWorker() { + try { + this.worker = new Worker( + new URL("./FEAWrapperScript.js", import.meta.url), + { + type: "module", + } + ); + + this.worker.onerror = (event) => { + console.error("FEAWorkerScript: Worker error:", event); + }; + const FEAWorkerWrapper = Comlink.wrap(this.worker); + + this.feaWorker = await new FEAWorkerWrapper(); + + this.isReady = true; + } catch (error) { + console.error("Failed to initialize worker", error); + throw error; + } + } + + async _ensureReady() { + if (this.isReady) return Promise.resolve(); + + return new Promise((resolve, reject) => { + let attempts = 0; + const maxAttempts = 50; // 5 seconds max + + const checkReady = () => { + attempts++; + if (this.isReady) { + resolve(); + } else if (attempts >= maxAttempts) { + reject(new Error("Timeout waiting for worker to be ready")); + } else { + setTimeout(checkReady, 1000); + } + }; + checkReady(); + }); + } + + async setSolverConfig(solverConfig) { + await this._ensureReady(); + basicLog(`FEAWorkerScript: Setting solver config to: ${solverConfig}`); + return this.feaWorker.setSolverConfig(solverConfig); + } + + async setMeshConfig(meshConfig) { + await this._ensureReady(); + basicLog(`FEAWorkerScript: Setting mesh config`); + return this.feaWorker.setMeshConfig(meshConfig); + } + + async addBoundaryCondition(boundaryKey, condition) { + await this._ensureReady(); + basicLog( + `FEAWorkerScript: Adding boundary condition for boundary: ${boundaryKey}` + ); + return this.feaWorker.addBoundaryCondition(boundaryKey, condition); + } + + async setSolverMethod(solverMethod) { + await this._ensureReady(); + basicLog(`FEAWorkerScript: Setting solver method to: ${solverMethod}`); + return this.feaWorker.setSolverMethod(solverMethod); + } + + async solve() { + await this._ensureReady(); + basicLog("FEAWorkerScript: Requesting solution from worker..."); + + const startTime = performance.now(); + const result = await this.feaWorker.solve(); + const endTime = performance.now(); + + basicLog( + `FEAWorkerScript: Solution completed in ${( + (endTime - startTime) / + 1000 + ).toFixed(2)}s` + ); + return result; + } + + async getModelInfo() { + await this._ensureReady(); + return this.feaWorker.getModelInfo(); + } + + async ping() { + await this._ensureReady(); + return this.feaWorker.ping(); + } + + terminate() { + if (this.worker) { + this.worker.terminate(); + this.worker = null; + this.feaWorker = null; + this.isReady = false; + } + } +} diff --git a/src/FEAWrapperScript.js b/src/FEAWrapperScript.js new file mode 100644 index 0000000..71db319 --- /dev/null +++ b/src/FEAWrapperScript.js @@ -0,0 +1,89 @@ +import * as Comlink from "https://unpkg.com/comlink/dist/esm/comlink.mjs"; +import { FEAScriptModel } from "./FEAScript.js"; +import { create, all } from "https://cdn.jsdelivr.net/npm/mathjs@latest/+esm"; + +const math = create(all); + +globalThis.math = math; + +class FEAWorkerWrapper { + constructor() { + try { + this.model = new FEAScriptModel(); + } catch (error) { + console.error("FEA Worker: Error initializing FEAScriptModel", error); + throw error; + } + } + + setSolverConfig(solverConfig) { + try { + this.model.setSolverConfig(solverConfig); + return true; + } catch (error) { + console.error("FEA Worker: Error in setSolverConfig", error); + throw error; + } + } + + setMeshConfig(meshConfig) { + try { + this.model.setMeshConfig(meshConfig); + return true; + } catch (error) { + console.error("FEA Worker: Error in setMeshConfig", error); + throw error; + } + } + + addBoundaryCondition(boundaryKey, condition) { + try { + this.model.addBoundaryCondition(boundaryKey, condition); + return true; + } catch (error) { + console.error("FEA Worker: Error in addBoundaryCondition", error); + throw error; + } + } + + setSolverMethod(solverMethod) { + try { + this.model.setSolverMethod(solverMethod); + return true; + } catch (error) { + console.error("FEA Worker: Error in setSolverMethod", error); + throw error; + } + } + + solve() { + try { + const result = this.model.solve(); + + return { + solutionVector: result.solutionVector, + nodesCoordinates: result.nodesCoordinates, + solverConfig: this.model.solverConfig, + meshDimension: this.model.meshConfig.meshDimension, + }; + } catch (error) { + console.error("FEA Worker: Error in solve", error); + throw error; + } + } + getModelInfo() { + try { + return { + solverConfig: this.model.solverConfig, + meshConfig: this.model.meshConfig, + boundaryConditions: this.model.boundaryConditions, + solverMethod: this.model.solverMethod, + }; + } catch (error) { + console.error("FEA Worker: Error in getModelInfo", error); + throw error; + } + } +} + +Comlink.expose(FEAWorkerWrapper); diff --git a/src/index.js b/src/index.js index a30abf7..a684ddb 100644 --- a/src/index.js +++ b/src/index.js @@ -11,3 +11,4 @@ export { FEAScriptModel } from "./FEAScript.js"; export { plotSolution } from "./visualization/plotSolutionScript.js"; export { printVersion, logSystem } from "./utilities/utilitiesScript.js"; +export { FEAWorkerScript } from "./FEAWorkerScript.js";