From 2d7b6ba67942eaf82989841155587feb2611432e Mon Sep 17 00:00:00 2001 From: nikoscham Date: Sun, 10 Aug 2025 11:37:18 +0300 Subject: [PATCH 01/24] Update README.md to include npm version badge --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 246fb70..fe152ab 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ FEAScript Logo # FEAScript-core +[![npm version](https://img.shields.io/npm/v/feascript)](https://www.npmjs.com/package/feascript) [FEAScript](https://feascript.com/) is a lightweight finite element simulation library built in JavaScript. It empowers users to create and execute simulations for physics and engineering applications in both browser-based and server-side environments. This is the core library of FEAScript. @@ -41,7 +42,7 @@ For browser-based examples and use cases, visit [our website tutorials](https:// ### Option 2: Via Node.js ```bash -# Install FEAScript and its peer dependencies +# Install FEAScript and its peer dependencies from npm npm install feascript mathjs plotly.js ``` From 15954475df1ce175e0e031e60f895b73f1757191 Mon Sep 17 00:00:00 2001 From: nikoscham Date: Thu, 21 Aug 2025 11:07:47 +0300 Subject: [PATCH 02/24] Refactor solver imports --- src/FEAScript.js | 3 +-- ...cobiMethodScript.js => jacobiSolverScript.js} | 2 +- ...stemScript.js => linearSystemSolverScript.js} | 16 ++++++++-------- src/methods/newtonRaphsonScript.js | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) rename src/methods/{jacobiMethodScript.js => jacobiSolverScript.js} (97%) rename src/methods/{linearSystemScript.js => linearSystemSolverScript.js} (82%) diff --git a/src/FEAScript.js b/src/FEAScript.js index b7fa4d8..ec7826a 100644 --- a/src/FEAScript.js +++ b/src/FEAScript.js @@ -9,9 +9,8 @@ // Website: https://feascript.com/ \__| // // Internal imports -import { jacobiMethod } from "./methods/jacobiMethodScript.js"; import { newtonRaphson } from "./methods/newtonRaphsonScript.js"; -import { solveLinearSystem } from "./methods/linearSystemScript.js"; +import { solveLinearSystem } from "./methods/linearSystemSolverScript.js"; import { assembleFrontPropagationMat } from "./solvers/frontPropagationScript.js"; import { assembleSolidHeatTransferMat } from "./solvers/solidHeatTransferScript.js"; import { basicLog, debugLog, errorLog } from "./utilities/loggingScript.js"; diff --git a/src/methods/jacobiMethodScript.js b/src/methods/jacobiSolverScript.js similarity index 97% rename from src/methods/jacobiMethodScript.js rename to src/methods/jacobiSolverScript.js index bc411f3..1e85de5 100644 --- a/src/methods/jacobiMethodScript.js +++ b/src/methods/jacobiSolverScript.js @@ -21,7 +21,7 @@ * - iterations: The number of iterations performed * - converged: Boolean indicating whether the method converged */ -export function jacobiMethod(jacobianMatrix, residualVector, initialGuess, options = {}) { +export function jacobiSolver(jacobianMatrix, residualVector, initialGuess, options = {}) { const { maxIterations = 1000, tolerance = 1e-6 } = options; const n = jacobianMatrix.length; // Size of the square matrix let x = [...initialGuess]; // Current solution (starts with initial guess) diff --git a/src/methods/linearSystemScript.js b/src/methods/linearSystemSolverScript.js similarity index 82% rename from src/methods/linearSystemScript.js rename to src/methods/linearSystemSolverScript.js index 18ccc4b..0fa0bec 100644 --- a/src/methods/linearSystemScript.js +++ b/src/methods/linearSystemSolverScript.js @@ -9,7 +9,7 @@ // Website: https://feascript.com/ \__| // // Internal imports -import { jacobiMethod } from "./jacobiMethodScript.js"; +import { jacobiSolver } from "./jacobiSolverScript.js"; import { basicLog, debugLog, errorLog } from "../utilities/loggingScript.js"; /** @@ -42,21 +42,21 @@ export function solveLinearSystem(solverMethod, jacobianMatrix, residualVector, } else if (solverMethod === "jacobi") { // Use Jacobi method const initialGuess = new Array(residualVector.length).fill(0); - const jacobiResult = jacobiMethod(jacobianMatrix, residualVector, initialGuess, { + const jacobiSolverResult = jacobiSolver(jacobianMatrix, residualVector, initialGuess, { maxIterations, tolerance, }); // Log convergence information - if (jacobiResult.converged) { - debugLog(`Jacobi method converged in ${jacobiResult.iterations} iterations`); + if (jacobiSolverResult.converged) { + debugLog(`Jacobi method converged in ${jacobiSolverResult.iterations} iterations`); } else { - debugLog(`Jacobi method did not converge after ${jacobiResult.iterations} iterations`); + debugLog(`Jacobi method did not converge after ${jacobiSolverResult.iterations} iterations`); } - solutionVector = jacobiResult.solutionVector; - converged = jacobiResult.converged; - iterations = jacobiResult.iterations; + solutionVector = jacobiSolverResult.solutionVector; + converged = jacobiSolverResult.converged; + iterations = jacobiSolverResult.iterations; } else { errorLog(`Unknown solver method: ${solverMethod}`); } diff --git a/src/methods/newtonRaphsonScript.js b/src/methods/newtonRaphsonScript.js index 42ae388..869d832 100644 --- a/src/methods/newtonRaphsonScript.js +++ b/src/methods/newtonRaphsonScript.js @@ -10,7 +10,7 @@ // Internal imports import { euclideanNorm } from "../methods/euclideanNormScript.js"; -import { solveLinearSystem } from "../methods/linearSystemScript.js"; +import { solveLinearSystem } from "./linearSystemSolverScript.js"; import { basicLog, debugLog, errorLog } from "../utilities/loggingScript.js"; import { calculateSystemSize } from "../utilities/helperFunctionsScript.js"; From ee2e429eb6ba5e6b374f2b7b889740c0873e7297 Mon Sep 17 00:00:00 2001 From: nikoscham Date: Fri, 22 Aug 2025 15:19:39 +0300 Subject: [PATCH 03/24] chore: bump version to 0.1.3 and update description in package.json - Updated version from 0.1.2 to 0.1.3 - Modified description for clarity - Added contributor Felipe Ferrari to package.json - Changed homepage URL to https://feascript.com/ - Updated version constant in src/index.js to 0.1.3 --- CONTRIBUTING.md | 19 +++++-- NOTICE.md | 12 ++--- README.md | 102 ++++++++++++++++++++++---------------- dist/feascript.cjs.js | 2 +- dist/feascript.cjs.js.map | 2 +- dist/feascript.esm.js | 2 +- dist/feascript.esm.js.map | 2 +- dist/feascript.umd.js | 2 +- dist/feascript.umd.js.map | 2 +- package.json | 10 ++-- src/index.js | 2 +- 11 files changed, 94 insertions(+), 63 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 47d724f..ee870bd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,11 +40,11 @@ To contribute a new feature or fix: All files in the FEAScript-core codebase should follow this structure: -1. **Banner**: All files start with the FEAScript ASCII art banner +1. **Banner**: All files start with the FEAScript ASCII art banner. 2. **Imports**: - - External imports (from npm packages) first, alphabetically ordered - - Internal imports next, grouped by module/folder -3. **Classes/Functions**: Implementation with proper JSDoc comments + - External imports (from npm packages) first, alphabetically ordered. + - Internal imports next, grouped by module/folder. +3. **Classes/Functions**: Implementation with proper JSDoc comments. Example: @@ -88,3 +88,14 @@ export class MyClass { } } ``` + +## File Naming Convention + +All JavaScript source files in FEAScript end with the suffix `Script` before the `.js` extension (e.g., `loggingScript.js`, `meshGenerationScript.js`, `newtonRaphsonScript.js`). This is an explicit, project‑level stylistic choice to: + +- Visually distinguish internal FEAScript modules from third‑party or external library files. +- Keep historical and stylistic consistency across the codebase. + +Exceptions: +- Public entry file: `index.js` (standard entry point convention). +- Core model file: `FEAScript.js` (matches the library name; appending "Script" would be redundant). diff --git a/NOTICE.md b/NOTICE.md index 511922e..b5d901d 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -1,16 +1,14 @@ FEAScript makes use of the following third-party software: 1. **math.js** - - License: Apache 2.0 License + - License: Apache 2.0 (https://github.com/josdejong/mathjs/blob/develop/LICENSE) - Source: https://github.com/josdejong/mathjs - - License: https://github.com/josdejong/mathjs/blob/develop/LICENSE + 2. **plotly.js** - - License: MIT License + - License: MIT (https://github.com/plotly/plotly.js/blob/master/LICENSE) - Source: https://github.com/plotly/plotly.js/tree/master - - License: https://github.com/plotly/plotly.js/blob/master/LICENSE 3. **Comlink** - - License: Apache 2.0 License - - Source: https://github.com/GoogleChromeLabs/comlink - - License: https://github.com/GoogleChromeLabs/comlink/blob/main/LICENSE \ No newline at end of file + - License: Apache 2.0 (https://github.com/GoogleChromeLabs/comlink/blob/main/LICENSE) + - Source: https://github.com/GoogleChromeLabs/comlink \ No newline at end of file diff --git a/README.md b/README.md index fe152ab..eaa9056 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,33 @@ FEAScript Logo # FEAScript-core -[![npm version](https://img.shields.io/npm/v/feascript)](https://www.npmjs.com/package/feascript) + +[![npm version](https://img.shields.io/npm/v/feascript)](https://www.npmjs.com/package/feascript) [FEAScript](https://feascript.com/) is a lightweight finite element simulation library built in JavaScript. It empowers users to create and execute simulations for physics and engineering applications in both browser-based and server-side environments. This is the core library of FEAScript. > 🚧 **FEAScript is currently under heavy development.** Functionality and interfaces may change rapidly as new features and enhancements are introduced. 🚧 +## Contents + +- [Installation](#installation) +- [Example Usage](#example-usage) +- [FEAScript Platform](#feascript-platform) +- [Contribute](#contribute) +- [License](#license) + ## Installation FEAScript is entirely implemented in pure JavaScript and can run in two environments: -1. **In the browser** with a simple HTML page, where all simulations are executed locally without any installations or using any cloud services -2. **Via Node.js** with plain JavaScript files, for server-side simulations +1. **In the browser** with a simple HTML page, where all simulations are executed locally without any installations or using any cloud services. +2. **Via Node.js** with plain JavaScript files, for server-side simulations. ### Option 1: In the Browser You can use FEAScript in browser environments in two ways: -**Direct Import from CDN**: -Add this to your HTML file: +**Direct Import from the Web (ES Module):** ```html ``` -**Download and Use Locally**: -1. Download the latest release from [GitHub Releases](https://github.com/FEAScript/FEAScript-core/releases) -2. Include it in your HTML file: +**Download and Use Locally:** ```html ``` -For browser-based examples and use cases, visit [our website tutorials](https://feascript.com/#tutorials). +You can Download the latest release from [GitHub Releases](https://github.com/FEAScript/FEAScript-core/releases). Explore various browser-based examples and use cases in our [website](https://feascript.com/#tutorials). ### Option 2: Via Node.js +Install FEAScript and its peer dependencies from npm: + ```bash -# Install FEAScript and its peer dependencies from npm npm install feascript mathjs plotly.js ``` -Then import it in your JavaScript/TypeScript file: +Then, import it in your JavaScript file: ```javascript import { FEAScriptModel } from "feascript"; ``` -**Important:** FEAScript is built as an ES module. If you're starting a completely new project (outside this repository), make sure to configure it to use ES modules by (when running examples from within this repository, this step is not needed as the root package.json already has the proper configuration): +**Important:** FEAScript is built as an ES module. If you're starting a completely new project (outside this repository), make sure to configure it to use ES modules by: ```bash # Create package.json with type=module for ES modules support echo '{"type":"module"}' > package.json ``` -Explore various Node.js examples and use cases [here](https://github.com/FEAScript/FEAScript-core/tree/main/examples). +When running examples from within this repository, this step is not needed as the root package.json already has the proper configuration. Explore various Node.js examples and use cases [here](https://github.com/FEAScript/FEAScript-core/tree/main/examples). ## Example Usage -**Browser Import:** -```javascript -// Import FEAScript library in browser -import { FEAScriptModel } from "https://core.feascript.com/dist/feascript.esm.js"; -``` +This is an indicative example of FEAScript, shown for execution in the browser. Adapt paths, solver types, and boundary conditions as needed for your specific problem: -**Node.js Import:** -```javascript -// Import FEAScript library in Node.js -import { FEAScriptModel } from "feascript"; -``` -```javascript -// Create and configure model -const model = new FEAScriptModel(); -model.setSolverConfig("solverType"); // e.g., "solidHeatTransfer" for a stationary solid heat transfer case -model.setMeshConfig({ - meshDimension: "1D" | "2D", // Mesh dimension - elementOrder: "linear" | "quadratic", // Element order - numElementsX: number, // Number of elements in x-direction - numElementsY: number, // Number of elements in y-direction (for 2D) - maxX: number, // Domain length in x-direction - maxY: number, // Domain length in y-direction (for 2D) -}); - -// Apply boundary conditions -model.addBoundaryCondition("boundaryIndex", ["conditionType", /* parameters */]); - -// Solve -model.setSolverMethod("linearSolver"); // lusolve (via mathjs) or jacobi -const { solutionVector, nodesCoordinates } = model.solve(); +```html + + + + + ``` +## FEAScript Platform + +For users who prefer a visual approach to creating simulations, we offer the [FEAScript platform](https://platform.feascript.com/) - a browser-based visual editor built on the [Blockly](https://developers.google.com/blockly) library. This no-code interface allows you to: + +- Build and run finite element simulations directly in your browser by connecting visual blocks +- Create complex simulations without writing any JavaScript code +- Save and load projects in XML format for easy sharing and reuse + +While FEAScript's JavaScript API offers full programmatic control for advanced customization, the FEAScript platform provides an accessible entry point for users without coding experience. + ## Contribute We warmly welcome contributors to help expand and refine FEAScript. Please see the [CONTRIBUTING.md](./CONTRIBUTING.md) file for detailed guidance on how to contribute. diff --git a/dist/feascript.cjs.js b/dist/feascript.cjs.js index 0291ca2..bc914b9 100644 --- a/dist/feascript.cjs.js +++ b/dist/feascript.cjs.js @@ -4,5 +4,5 @@ * Copyright 2019 Google LLC * SPDX-License-Identifier: Apache-2.0 */ -const p=Symbol("Comlink.proxy"),g=Symbol("Comlink.endpoint"),y=Symbol("Comlink.releaseProxy"),b=Symbol("Comlink.finalizer"),E=Symbol("Comlink.thrown"),$=e=>"object"==typeof e&&null!==e||"function"==typeof e,M=new Map([["proxy",{canHandle:e=>$(e)&&e[p],serialize(e){const{port1:t,port2:n}=new MessageChannel;return v(e,t),[n,[n]]},deserialize:e=>(e.start(),w(e))}],["throw",{canHandle:e=>$(e)&&E in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function v(e,t=globalThis,n=["*"]){t.addEventListener("message",(function s(o){if(!o||!o.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,o.origin))return void console.warn(`Invalid origin '${o.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},o.data),l=(o.data.argumentList||[]).map(k);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=k(o.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[p]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;v(e,n),d=function(e,t){return F.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[E]:0}}Promise.resolve(d).catch((e=>({value:e,[E]:0}))).then((n=>{const[o,a]=X(n);t.postMessage(Object.assign(Object.assign({},o),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",s),C(t),b in e&&"function"==typeof e[b]&&e[b]())})).catch((e=>{const[n,s]=X({value:new TypeError("Unserializable return value"),[E]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),s)}))})),t.start&&t.start()}function C(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function w(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const s=n.get(t.id);if(s)try{s(t)}finally{n.delete(t.id)}})),D(e,n,[],t)}function x(e){if(e)throw new Error("Proxy has been released and is not useable")}function S(e){return T(e,new Map,{type:"RELEASE"}).then((()=>{C(e)}))}const N=new WeakMap,O="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(N.get(e)||0)-1;N.set(e,t),0===t&&S(e)}));function D(e,t,n=[],s=function(){}){let o=!1;const i=new Proxy(s,{get(s,r){if(x(o),r===y)return()=>{!function(e){O&&O.unregister(e)}(i),S(e),t.clear(),o=!0};if("then"===r){if(0===n.length)return{then:()=>i};const s=T(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(k);return s.then.bind(s)}return D(e,t,[...n,r])},set(s,i,r){x(o);const[a,l]=X(r);return T(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(k)},apply(s,i,r){x(o);const a=n[n.length-1];if(a===g)return T(e,t,{type:"ENDPOINT"}).then(k);if("bind"===a)return D(e,t,n.slice(0,-1));const[l,d]=A(r);return T(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(k)},construct(s,i){x(o);const[r,a]=A(i);return T(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(k)}});return function(e,t){const n=(N.get(t)||0)+1;N.set(t,n),O&&O.register(e,t,e)}(i,e),i}function A(e){const t=e.map(X);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const F=new WeakMap;function X(e){for(const[t,n]of M)if(n.canHandle(e)){const[s,o]=n.serialize(e);return[{type:"HANDLER",name:t,value:s},o]}return[{type:"RAW",value:e},F.get(e)||[]]}function k(e){switch(e.type){case"HANDLER":return M.get(e.name).deserialize(e.value);case"RAW":return e.value}}function T(e,t,n,s){return new Promise((o=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,o),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),s)}))}exports.FEAScriptModel=class{constructor(){this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",s("FEAScriptModel instance created")}setSolverConfig(e){this.solverConfig=e,n(`Solver config set to: ${e}`)}setMeshConfig(e){this.meshConfig=e,n(`Mesh config set with dimensions: ${e.meshDimension}`)}addBoundaryCondition(e,t){this.boundaryConditions[e]=t,n(`Boundary condition added for boundary: ${e}, type: ${t[0]}`)}setSolverMethod(e){this.solverMethod=e,n(`Solver method set to: ${e}`)}solve(){if(!this.solverConfig||!this.meshConfig||!this.boundaryConditions){const e="Solver config, mesh config, and boundary conditions must be set before solving.";throw console.error(e),new Error(e)}let e=[],t=[],a=[],d=[],p={};if(s("Beginning solving process..."),console.time("totalSolvingTime"),"solidHeatTransferScript"===this.solverConfig){s(`Using solver: ${this.solverConfig}`),({jacobianMatrix:e,residualVector:t,nodesCoordinates:p}=function(e,t){s("Starting solid heat transfer matrix assembly...");const{meshDimension:i,numElementsX:r,numElementsY:a,maxX:d,maxY:c,elementOrder:p,parsedMesh:g}=e;let y;n("Generating mesh..."),"1D"===i?y=new m({numElementsX:r,maxX:d,elementOrder:p,parsedMesh:g}):"2D"===i?y=new h({numElementsX:r,maxX:d,numElementsY:a,maxY:c,elementOrder:p,parsedMesh:g}):o("Mesh dimension must be either '1D' or '2D'.");const b=y.boundaryElementsProcessed?y.parsedMesh:y.generateMesh();let E,$,M=b.nodesXCoordinates,v=b.nodesYCoordinates,C=b.totalNodesX,w=b.totalNodesY,x=b.nodalNumbering,S=b.boundaryElements;null!=g?(E=x.length,$=M.length,n(`Using parsed mesh with ${E} elements and ${$} nodes`)):(E=r*("2D"===i?a:1),$=C*("2D"===i?w:1),n(`Using mesh generated from geometry with ${E} elements and ${$} nodes`));let N,O,D,A,F,X,k,T=[],P=[],Y=[],R=[],W=[],I=[],B=[],j=[],q=[],V=[];for(let e=0;e<$;e++){q[e]=0,V.push([]);for(let t=0;t<$;t++)V[e][t]=0}const L=new l({meshDimension:i,elementOrder:p});let G=new u({meshDimension:i,elementOrder:p}).getGaussPointsAndWeights();P=G.gaussPoints,Y=G.gaussWeights;const U=x[0].length;for(let e=0;e0&&(o.initialSolution=[...a]);const s=r(c,o,100,1e-4);e=s.jacobianMatrix,t=s.residualVector,p=s.nodesCoordinates,a=s.solutionVector,n+=.2}}return console.timeEnd("totalSolvingTime"),s("Solving process completed"),{solutionVector:a,nodesCoordinates:p}}},exports.FEAScriptWorker=class{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js","undefined"==typeof document?new(require("url").URL)("file:"+__filename).href:document.currentScript&&"SCRIPT"===document.currentScript.tagName.toUpperCase()&&document.currentScript.src||new URL("feascript.cjs.js",document.baseURI).href),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=w(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const s=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(s,1e3)};s()}))}async setSolverConfig(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),s("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),s(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),s("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return s(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}},exports.VERSION="0.1.2",exports.importGmshQuadTri=async e=>{let t={nodesXCoordinates:[],nodesYCoordinates:[],nodalNumbering:{quadElements:[],triangleElements:[]},boundaryElements:[],boundaryConditions:[],boundaryNodePairs:{},gmshV:0,ascii:!1,fltBytes:"8",totalNodesX:0,totalNodesY:0,physicalPropMap:[],elementTypes:{}},s=(await e.text()).split("\n").map((e=>e.trim())).filter((e=>""!==e&&" "!==e)),o="",i=0,r=0,a=0,l=0,d={numNodes:0},m=0,h=[],u=0,c=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},g=0,y={};for(;i""!==e));if("meshFormat"===o)t.gmshV=parseFloat(n[0]),t.ascii="0"===n[1],t.fltBytes=n[2];else if("physicalNames"===o){if(n.length>=3){if(!/^\d+$/.test(n[0])){i++;continue}const e=parseInt(n[0],10),s=parseInt(n[1],10);let o=n.slice(2).join(" ");o=o.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:s,dimension:e,name:o})}}else if("nodes"===o){if(0===r){r=parseInt(n[0],10),a=parseInt(n[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;y[n]||(y[n]=[]),y[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);g++,g===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=y[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),n(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t},exports.logSystem=function(e){"basic"!==e&&"debug"!==e?(console.log("%c[WARN] Invalid log level: "+e+". Using basic instead.","color: #FFC107; font-weight: bold;"),t="basic"):(t=e,s(`Log level set to: ${e}`))},exports.plotSolution=function(e,t,n,s,o,i,r="structured"){const{nodesXCoordinates:a,nodesYCoordinates:l}=t;if("1D"===s&&"line"===o){let t;t=e.length>0&&Array.isArray(e[0])?e.map((e=>e[0])):e;let s=Array.from(a),o={x:s,y:t,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},r=Math.min(window.innerWidth,700),l=Math.max(...s),d=r/l,m={title:`line plot - ${n}`,width:Math.max(d*l,400),height:350,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:70,r:40,t:50,b:50}};Plotly.newPlot(i,[o],m,{responsive:!0})}else if("2D"===s&&"contour"===o){const t="structured"===r,s=new Set(a).size,d=new Set(l).size;let m;m=Array.isArray(e[0])?e.map((e=>e[0])):e;let h=Math.min(window.innerWidth,700),u=Math.max(...a),c=Math.max(...l)/u,f=Math.min(h,600),p={title:`${o} plot - ${n}`,width:f,height:f*c*.8,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"};if(t){const t=s,n=d;math.reshape(Array.from(a),[t,n]);let o=math.reshape(Array.from(l),[t,n]),r=math.reshape(Array.from(e),[t,n]),m=math.transpose(r),h=[];for(let e=0;e"object"==typeof e&&null!==e||"function"==typeof e,M=new Map([["proxy",{canHandle:e=>$(e)&&e[p],serialize(e){const{port1:t,port2:n}=new MessageChannel;return v(e,t),[n,[n]]},deserialize:e=>(e.start(),w(e))}],["throw",{canHandle:e=>$(e)&&E in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function v(e,t=globalThis,n=["*"]){t.addEventListener("message",(function s(o){if(!o||!o.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,o.origin))return void console.warn(`Invalid origin '${o.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},o.data),l=(o.data.argumentList||[]).map(k);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=k(o.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[p]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;v(e,n),d=function(e,t){return F.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[E]:0}}Promise.resolve(d).catch((e=>({value:e,[E]:0}))).then((n=>{const[o,a]=X(n);t.postMessage(Object.assign(Object.assign({},o),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",s),C(t),b in e&&"function"==typeof e[b]&&e[b]())})).catch((e=>{const[n,s]=X({value:new TypeError("Unserializable return value"),[E]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),s)}))})),t.start&&t.start()}function C(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function w(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const s=n.get(t.id);if(s)try{s(t)}finally{n.delete(t.id)}})),D(e,n,[],t)}function x(e){if(e)throw new Error("Proxy has been released and is not useable")}function S(e){return T(e,new Map,{type:"RELEASE"}).then((()=>{C(e)}))}const N=new WeakMap,O="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(N.get(e)||0)-1;N.set(e,t),0===t&&S(e)}));function D(e,t,n=[],s=function(){}){let o=!1;const i=new Proxy(s,{get(s,r){if(x(o),r===y)return()=>{!function(e){O&&O.unregister(e)}(i),S(e),t.clear(),o=!0};if("then"===r){if(0===n.length)return{then:()=>i};const s=T(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(k);return s.then.bind(s)}return D(e,t,[...n,r])},set(s,i,r){x(o);const[a,l]=X(r);return T(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(k)},apply(s,i,r){x(o);const a=n[n.length-1];if(a===g)return T(e,t,{type:"ENDPOINT"}).then(k);if("bind"===a)return D(e,t,n.slice(0,-1));const[l,d]=A(r);return T(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(k)},construct(s,i){x(o);const[r,a]=A(i);return T(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(k)}});return function(e,t){const n=(N.get(t)||0)+1;N.set(t,n),O&&O.register(e,t,e)}(i,e),i}function A(e){const t=e.map(X);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const F=new WeakMap;function X(e){for(const[t,n]of M)if(n.canHandle(e)){const[s,o]=n.serialize(e);return[{type:"HANDLER",name:t,value:s},o]}return[{type:"RAW",value:e},F.get(e)||[]]}function k(e){switch(e.type){case"HANDLER":return M.get(e.name).deserialize(e.value);case"RAW":return e.value}}function T(e,t,n,s){return new Promise((o=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,o),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),s)}))}exports.FEAScriptModel=class{constructor(){this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",s("FEAScriptModel instance created")}setSolverConfig(e){this.solverConfig=e,n(`Solver config set to: ${e}`)}setMeshConfig(e){this.meshConfig=e,n(`Mesh config set with dimensions: ${e.meshDimension}`)}addBoundaryCondition(e,t){this.boundaryConditions[e]=t,n(`Boundary condition added for boundary: ${e}, type: ${t[0]}`)}setSolverMethod(e){this.solverMethod=e,n(`Solver method set to: ${e}`)}solve(){if(!this.solverConfig||!this.meshConfig||!this.boundaryConditions){const e="Solver config, mesh config, and boundary conditions must be set before solving.";throw console.error(e),new Error(e)}let e=[],t=[],a=[],d=[],p={};if(s("Beginning solving process..."),console.time("totalSolvingTime"),"solidHeatTransferScript"===this.solverConfig){s(`Using solver: ${this.solverConfig}`),({jacobianMatrix:e,residualVector:t,nodesCoordinates:p}=function(e,t){s("Starting solid heat transfer matrix assembly...");const{meshDimension:i,numElementsX:r,numElementsY:a,maxX:d,maxY:c,elementOrder:p,parsedMesh:g}=e;let y;n("Generating mesh..."),"1D"===i?y=new m({numElementsX:r,maxX:d,elementOrder:p,parsedMesh:g}):"2D"===i?y=new h({numElementsX:r,maxX:d,numElementsY:a,maxY:c,elementOrder:p,parsedMesh:g}):o("Mesh dimension must be either '1D' or '2D'.");const b=y.boundaryElementsProcessed?y.parsedMesh:y.generateMesh();let E,$,M=b.nodesXCoordinates,v=b.nodesYCoordinates,C=b.totalNodesX,w=b.totalNodesY,x=b.nodalNumbering,S=b.boundaryElements;null!=g?(E=x.length,$=M.length,n(`Using parsed mesh with ${E} elements and ${$} nodes`)):(E=r*("2D"===i?a:1),$=C*("2D"===i?w:1),n(`Using mesh generated from geometry with ${E} elements and ${$} nodes`));let N,O,D,A,F,X,k,T=[],P=[],Y=[],R=[],W=[],I=[],B=[],j=[],q=[],V=[];for(let e=0;e<$;e++){q[e]=0,V.push([]);for(let t=0;t<$;t++)V[e][t]=0}const L=new l({meshDimension:i,elementOrder:p});let G=new u({meshDimension:i,elementOrder:p}).getGaussPointsAndWeights();P=G.gaussPoints,Y=G.gaussWeights;const U=x[0].length;for(let e=0;e0&&(o.initialSolution=[...a]);const s=r(c,o,100,1e-4);e=s.jacobianMatrix,t=s.residualVector,p=s.nodesCoordinates,a=s.solutionVector,n+=.2}}return console.timeEnd("totalSolvingTime"),s("Solving process completed"),{solutionVector:a,nodesCoordinates:p}}},exports.FEAScriptWorker=class{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js","undefined"==typeof document?new(require("url").URL)("file:"+__filename).href:document.currentScript&&"SCRIPT"===document.currentScript.tagName.toUpperCase()&&document.currentScript.src||new URL("feascript.cjs.js",document.baseURI).href),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=w(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const s=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(s,1e3)};s()}))}async setSolverConfig(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),s("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),s(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),s("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return s(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}},exports.VERSION="0.1.3",exports.importGmshQuadTri=async e=>{let t={nodesXCoordinates:[],nodesYCoordinates:[],nodalNumbering:{quadElements:[],triangleElements:[]},boundaryElements:[],boundaryConditions:[],boundaryNodePairs:{},gmshV:0,ascii:!1,fltBytes:"8",totalNodesX:0,totalNodesY:0,physicalPropMap:[],elementTypes:{}},s=(await e.text()).split("\n").map((e=>e.trim())).filter((e=>""!==e&&" "!==e)),o="",i=0,r=0,a=0,l=0,d={numNodes:0},m=0,h=[],u=0,c=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},g=0,y={};for(;i""!==e));if("meshFormat"===o)t.gmshV=parseFloat(n[0]),t.ascii="0"===n[1],t.fltBytes=n[2];else if("physicalNames"===o){if(n.length>=3){if(!/^\d+$/.test(n[0])){i++;continue}const e=parseInt(n[0],10),s=parseInt(n[1],10);let o=n.slice(2).join(" ");o=o.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:s,dimension:e,name:o})}}else if("nodes"===o){if(0===r){r=parseInt(n[0],10),a=parseInt(n[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;y[n]||(y[n]=[]),y[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);g++,g===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=y[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),n(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t},exports.logSystem=function(e){"basic"!==e&&"debug"!==e?(console.log("%c[WARN] Invalid log level: "+e+". Using basic instead.","color: #FFC107; font-weight: bold;"),t="basic"):(t=e,s(`Log level set to: ${e}`))},exports.plotSolution=function(e,t,n,s,o,i,r="structured"){const{nodesXCoordinates:a,nodesYCoordinates:l}=t;if("1D"===s&&"line"===o){let t;t=e.length>0&&Array.isArray(e[0])?e.map((e=>e[0])):e;let s=Array.from(a),o={x:s,y:t,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},r=Math.min(window.innerWidth,700),l=Math.max(...s),d=r/l,m={title:`line plot - ${n}`,width:Math.max(d*l,400),height:350,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:70,r:40,t:50,b:50}};Plotly.newPlot(i,[o],m,{responsive:!0})}else if("2D"===s&&"contour"===o){const t="structured"===r,s=new Set(a).size,d=new Set(l).size;let m;m=Array.isArray(e[0])?e.map((e=>e[0])):e;let h=Math.min(window.innerWidth,700),u=Math.max(...a),c=Math.max(...l)/u,f=Math.min(h,600),p={title:`${o} plot - ${n}`,width:f,height:f*c*.8,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"};if(t){const t=s,n=d;math.reshape(Array.from(a),[t,n]);let o=math.reshape(Array.from(l),[t,n]),r=math.reshape(Array.from(e),[t,n]),m=math.transpose(r),h=[];for(let e=0;e 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n nodesCoordinates,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Helper function to calculate system size from mesh configuration\n * @param {object} meshConfig - Mesh configuration object\n * @returns {number} Total number of nodes in the system\n */\nexport function calculateSystemSize(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, elementOrder, parsedMesh } = meshConfig;\n\n if (parsedMesh && parsedMesh.nodesXCoordinates) {\n // For parsed meshes (like from GMSH)\n return parsedMesh.nodesXCoordinates.length;\n } else {\n // For geometry-based meshes\n let nodesX,\n nodesY = 1;\n\n if (elementOrder === \"linear\") {\n nodesX = numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = numElementsY + 1;\n } else if (elementOrder === \"quadratic\") {\n nodesX = 2 * numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = 2 * numElementsY + 1;\n }\n\n return nodesX * nodesY;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n debugLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n if (\n this.numElementsX === null ||\n this.maxX === null ||\n this.numElementsY === null ||\n this.maxY === null\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n \n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\n\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the front propagation matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation (ranges from 0 to 1)\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleFrontPropagationMat(\n meshConfig,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n // TODO: The mesh generation step should be moved outside of the assembleFrontPropagationMat function so that not performed in every Newton-Raphson iteration\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n let solutionDerivX; // The x-derivative of the solution\n let solutionDerivY; // The y-derivative of the solution\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n detJacobian = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n detJacobian = ksiDerivX;\n }\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n // 2D front propagation (eikonal) equation\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n solutionDerivX = 0;\n solutionDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x & y-derivatives of basis functions and x & y-derivatives of the solution\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n // The x-derivative of the solution\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n // The y-derivative of the solution\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector - Viscous term: Add diffusion contribution to stabilize the solution\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n // residualVector - Eikonal term: Add the eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix - Viscous term: Add the Jacobian contribution from the diffusion term\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n // jacobianMatrix - Eikonal term: Add the Jacobian contribution from the eikonal equation\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n (detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)\n ) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n }\n\n // Create an instance of GenericBoundaryConditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions (Robin type)\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiMethod } from \"./methods/jacobiMethodScript.js\";\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n let nodesCoordinates = {};\n let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term - Used in frontPropagationScript\n let newtonRaphsonIterations;\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleSolidHeatTransferMat(\n this.meshConfig,\n this.boundaryConditions\n ));\n\n // Solve the assembled linear system\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n\n // Create context object with all necessary properties\n const context = {\n meshConfig: this.meshConfig,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n nodesCoordinates = newtonRaphsonResult.nodesCoordinates;\n solutionVector = newtonRaphsonResult.solutionVector;\n newtonRaphsonIterations = newtonRaphsonResult.iterations;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the solid heat transfer matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n // 2D solid heat transfer\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Create an instance of ThermalBoundaryConditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.2\";","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","debugLog","message","console","log","basicLog","errorLog","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","math","lusolve","jacobiResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiMethod","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","nodesCoordinates","totalNodes","meshConfig","meshDimension","numElementsX","numElementsY","elementOrder","parsedMesh","nodesXCoordinates","nodesX","nodesY","calculateSystemSize","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","GenericBoundaryConditions","constructor","boundaryElements","nop","this","imposeConstantValueBoundaryConditions","Object","keys","forEach","boundaryKey","value","elementIndex","side","nodeIndex","globalNodeIndex","colIndex","BasisFunctions","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","maxX","maxY","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","undefined","fixedBoundaryElements","boundaryNodePairs","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","generate1DNodalNumbering","findBoundaryElements","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","assembleFrontPropagationMat","eikonalViscousTerm","mesh","nodesCoordinatesAndNumbering","totalElements","xCoordinates","yCoordinates","ksiDerivX","etaDerivX","ksiDerivY","etaDerivY","detJacobian","solutionDerivX","solutionDerivY","localToGlobalMap","basisFunctionDerivX","basisFunctionDerivY","basisFunctions","gaussPointsAndWeights","numNodes","localNodeIndex","gaussPointIndex1","basisFunctionsAndDerivatives","gaussPointIndex2","localNodeIndex1","localToGlobalMap1","localNodeIndex2","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","Error","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","map","fromWireValue","returnValue","parent","slice","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","r","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","arr","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","thermalBoundaryConditions","assembleSolidHeatTransferMat","newtonRaphsonResult","worker","feaWorker","isReady","_initWorker","Worker","URL","document","require","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","result","toFixed","getModelInfo","ping","terminate","async","file","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","parseInt","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","level","plotType","plotDivId","meshType","yData","xData","from","lineData","mode","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","l","t","b","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"feascript.cjs.js","sources":["../src/methods/euclideanNormScript.js","../src/utilities/loggingScript.js","../src/methods/linearSystemSolverScript.js","../src/methods/jacobiSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/utilities/helperFunctionsScript.js","../src/solvers/genericBoundaryConditionsScript.js","../src/mesh/basisFunctionsScript.js","../src/mesh/meshGenerationScript.js","../src/methods/numericalIntegrationScript.js","../src/solvers/frontPropagationScript.js","../src/solvers/thermalBoundaryConditionsScript.js","../src/vendor/comlink.mjs","../src/FEAScript.js","../src/solvers/solidHeatTransferScript.js","../src/workers/workerScript.js","../src/index.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.js"],"sourcesContent":["// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to calculate the Euclidean norm of a vector\n * @param {array} vector - The input vector\n * @returns {number} The Euclidean norm of the vector\n */\nexport function euclideanNorm(vector) {\n let norm = 0;\n for (let i = 0; i < vector.length; i++) {\n norm += vector[i] * vector[i];\n }\n norm = Math.sqrt(norm);\n return norm;\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Global logging level\nlet currentLogLevel = \"basic\";\n\n/**\n * Function to set the logging system level\n * @param {string} level - Logging level (basic, debug)\n */\nexport function logSystem(level) {\n if (level !== \"basic\" && level !== \"debug\") {\n console.log(\n \"%c[WARN] Invalid log level: \" + level + \". Using basic instead.\",\n \"color: #FFC107; font-weight: bold;\"\n ); // Yellow for warnings\n currentLogLevel = \"basic\";\n } else {\n currentLogLevel = level;\n basicLog(`Log level set to: ${level}`);\n }\n}\n\n/**\n * Function to log debug messages - only logs if level is 'debug'\n * @param {string} message - Message to log\n */\nexport function debugLog(message) {\n if (currentLogLevel === \"debug\") {\n console.log(\"%c[DEBUG] \" + message, \"color: #2196F3; font-weight: bold;\"); // Blue color for debug\n }\n}\n\n/**\n * Function to log basic information - always logs\n * @param {string} message - Message to log\n */\nexport function basicLog(message) {\n console.log(\"%c[INFO] \" + message, \"color: #4CAF50; font-weight: bold;\"); // Green color for basic info\n}\n\n/**\n * Function to log error messages\n * @param {string} message - Message to log\n */\nexport function errorLog(message) {\n console.log(\"%c[ERROR] \" + message, \"color: #F44336; font-weight: bold;\"); // Red color for errors\n}\n\n/**\n * Function to handle version information and fetch the latest update date and release from GitHub\n */\nexport async function printVersion() {\n basicLog(\"Fetching latest FEAScript version information...\");\n try {\n const commitResponse = await fetch(\"https://api.github.com/repos/FEAScript/FEAScript/commits/main\");\n const commitData = await commitResponse.json();\n const latestCommitDate = new Date(commitData.commit.committer.date).toLocaleString();\n basicLog(`Latest FEAScript update: ${latestCommitDate}`);\n return latestCommitDate;\n } catch (error) {\n errorLog(\"Failed to fetch version information: \" + error);\n return \"Version information unavailable\";\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiSolver } from \"./jacobiSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to solve a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (\"lusolve\" or \"jacobi\")\n * @param {Array} jacobianMatrix - The coefficient matrix\n * @param {Array} residualVector - The right-hand side vector\n * @param {object} [options] - Additional options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum iterations for iterative methods\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance for iterative methods\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - converged: Boolean indicating whether the method converged (for iterative methods)\n * - iterations: Number of iterations performed (for iterative methods)\n */\nexport function solveLinearSystem(solverMethod, jacobianMatrix, residualVector, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n\n let solutionVector = [];\n let converged = true;\n let iterations = 0;\n\n // Solve the linear system based on the specified solver method\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n if (solverMethod === \"lusolve\") {\n // Use LU decomposition method\n solutionVector = math.lusolve(jacobianMatrix, residualVector);\n } else if (solverMethod === \"jacobi\") {\n // Use Jacobi method\n const initialGuess = new Array(residualVector.length).fill(0);\n const jacobiSolverResult = jacobiSolver(jacobianMatrix, residualVector, initialGuess, {\n maxIterations,\n tolerance,\n });\n\n // Log convergence information\n if (jacobiSolverResult.converged) {\n debugLog(`Jacobi method converged in ${jacobiSolverResult.iterations} iterations`);\n } else {\n debugLog(`Jacobi method did not converge after ${jacobiSolverResult.iterations} iterations`);\n }\n\n solutionVector = jacobiSolverResult.solutionVector;\n converged = jacobiSolverResult.converged;\n iterations = jacobiSolverResult.iterations;\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n return { solutionVector, converged, iterations };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method\n * @param {array} jacobianMatrix - The coefficient matrix (must be square)\n * @param {array} residualVector - The right-hand side vector\n * @param {array} initialGuess - Initial guess for solution vector\n * @param {object} [options] - Options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum number of iterations\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\nexport function jacobiSolver(jacobianMatrix, residualVector, initialGuess, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n const n = jacobianMatrix.length; // Size of the square matrix\n let x = [...initialGuess]; // Current solution (starts with initial guess)\n let xNew = new Array(n); // Next iteration's solution\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n // Perform one iteration\n for (let i = 0; i < n; i++) {\n let sum = 0;\n // Calculate sum of jacobianMatrix[i][j] * x[j] for j ≠ i\n for (let j = 0; j < n; j++) {\n if (j !== i) {\n sum += jacobianMatrix[i][j] * x[j];\n }\n }\n // Update xNew[i] using the Jacobi formula\n xNew[i] = (residualVector[i] - sum) / jacobianMatrix[i][i];\n }\n\n // Check convergence\n let maxDiff = 0;\n for (let i = 0; i < n; i++) {\n maxDiff = Math.max(maxDiff, Math.abs(xNew[i] - x[i]));\n }\n\n // Update x for next iteration\n x = [...xNew];\n\n // Successfully converged if maxDiff is less than tolerance\n if (maxDiff < tolerance) {\n return {\n solutionVector: x,\n iterations: iteration + 1,\n converged: true,\n };\n }\n }\n\n // maxIterations were reached without convergence\n return {\n solutionVector: x,\n iterations: maxIterations,\n converged: false,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { euclideanNorm } from \"../methods/euclideanNormScript.js\";\nimport { solveLinearSystem } from \"./linearSystemSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\nimport { calculateSystemSize } from \"../utilities/helperFunctionsScript.js\";\n\n/**\n * Function to solve a system of nonlinear equations using the Newton-Raphson method\n * @param {number} [maxIterations=100] - Maximum number of iterations\n * @param {number} [tolerance=1e-4] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\n\nexport function newtonRaphson(assembleMat, context, maxIterations = 100, tolerance = 1e-4) {\n let errorNorm = 0;\n let converged = false;\n let iterations = 0;\n let deltaX = [];\n let solutionVector = [];\n let jacobianMatrix = [];\n let residualVector = [];\n let nodesCoordinates = {};\n\n // Calculate system size directly from meshConfig\n let totalNodes = calculateSystemSize(context.meshConfig);\n\n // Initialize arrays with proper size\n for (let i = 0; i < totalNodes; i++) {\n deltaX[i] = 0;\n solutionVector[i] = 0;\n }\n\n // Initialize solution from context if available\n if (context.initialSolution && context.initialSolution.length === totalNodes) {\n solutionVector = [...context.initialSolution];\n }\n\n while (iterations < maxIterations && !converged) {\n // Update solution\n for (let i = 0; i < solutionVector.length; i++) {\n solutionVector[i] = Number(solutionVector[i]) + Number(deltaX[i]);\n }\n\n // Compute Jacobian and residual matrices\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleMat(\n context.meshConfig,\n context.boundaryConditions,\n solutionVector, // The solution vector is required in the case of a non-linear equation\n context.eikonalActivationFlag\n ));\n\n // Solve the linear system based on the specified solver method\n const linearSystemResult = solveLinearSystem(context.solverMethod, jacobianMatrix, residualVector);\n deltaX = linearSystemResult.solutionVector;\n\n // Check convergence\n errorNorm = euclideanNorm(deltaX);\n\n // Norm for each iteration\n basicLog(`Newton-Raphson iteration ${iterations + 1}: Error norm = ${errorNorm.toExponential(4)}`);\n\n if (errorNorm <= tolerance) {\n converged = true;\n } else if (errorNorm > 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n nodesCoordinates,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Helper function to calculate system size from mesh configuration\n * @param {object} meshConfig - Mesh configuration object\n * @returns {number} Total number of nodes in the system\n */\nexport function calculateSystemSize(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, elementOrder, parsedMesh } = meshConfig;\n\n if (parsedMesh && parsedMesh.nodesXCoordinates) {\n // For parsed meshes (like from GMSH)\n return parsedMesh.nodesXCoordinates.length;\n } else {\n // For geometry-based meshes\n let nodesX,\n nodesY = 1;\n\n if (elementOrder === \"linear\") {\n nodesX = numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = numElementsY + 1;\n } else if (elementOrder === \"quadratic\") {\n nodesX = 2 * numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = 2 * numElementsY + 1;\n }\n\n return nodesX * nodesY;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n debugLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n if (\n this.numElementsX === null ||\n this.maxX === null ||\n this.numElementsY === null ||\n this.maxY === null\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n \n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\n\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the front propagation matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation (ranges from 0 to 1)\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleFrontPropagationMat(\n meshConfig,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n // TODO: The mesh generation step should be moved outside of the assembleFrontPropagationMat function so that not performed in every Newton-Raphson iteration\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n let solutionDerivX; // The x-derivative of the solution\n let solutionDerivY; // The y-derivative of the solution\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n detJacobian = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n detJacobian = ksiDerivX;\n }\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n // 2D front propagation (eikonal) equation\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n solutionDerivX = 0;\n solutionDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x & y-derivatives of basis functions and x & y-derivatives of the solution\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n // The x-derivative of the solution\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n // The y-derivative of the solution\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector - Viscous term: Add diffusion contribution to stabilize the solution\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n // residualVector - Eikonal term: Add the eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix - Viscous term: Add the Jacobian contribution from the diffusion term\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n // jacobianMatrix - Eikonal term: Add the Jacobian contribution from the eikonal equation\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n (detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)\n ) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n }\n\n // Create an instance of GenericBoundaryConditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions (Robin type)\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n let nodesCoordinates = {};\n let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term - Used in frontPropagationScript\n let newtonRaphsonIterations;\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleSolidHeatTransferMat(\n this.meshConfig,\n this.boundaryConditions\n ));\n\n // Solve the assembled linear system\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n\n // Create context object with all necessary properties\n const context = {\n meshConfig: this.meshConfig,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n nodesCoordinates = newtonRaphsonResult.nodesCoordinates;\n solutionVector = newtonRaphsonResult.solutionVector;\n newtonRaphsonIterations = newtonRaphsonResult.iterations;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the solid heat transfer matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n // 2D solid heat transfer\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Create an instance of ThermalBoundaryConditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.3\";","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","debugLog","message","console","log","basicLog","errorLog","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","math","lusolve","jacobiSolverResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiSolver","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","nodesCoordinates","totalNodes","meshConfig","meshDimension","numElementsX","numElementsY","elementOrder","parsedMesh","nodesXCoordinates","nodesX","nodesY","calculateSystemSize","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","GenericBoundaryConditions","constructor","boundaryElements","nop","this","imposeConstantValueBoundaryConditions","Object","keys","forEach","boundaryKey","value","elementIndex","side","nodeIndex","globalNodeIndex","colIndex","BasisFunctions","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","maxX","maxY","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","undefined","fixedBoundaryElements","boundaryNodePairs","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","generate1DNodalNumbering","findBoundaryElements","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","assembleFrontPropagationMat","eikonalViscousTerm","mesh","nodesCoordinatesAndNumbering","totalElements","xCoordinates","yCoordinates","ksiDerivX","etaDerivX","ksiDerivY","etaDerivY","detJacobian","solutionDerivX","solutionDerivY","localToGlobalMap","basisFunctionDerivX","basisFunctionDerivY","basisFunctions","gaussPointsAndWeights","numNodes","localNodeIndex","gaussPointIndex1","basisFunctionsAndDerivatives","gaussPointIndex2","localNodeIndex1","localToGlobalMap1","localNodeIndex2","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","Error","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","map","fromWireValue","returnValue","parent","slice","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","r","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","arr","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","thermalBoundaryConditions","assembleSolidHeatTransferMat","newtonRaphsonResult","worker","feaWorker","isReady","_initWorker","Worker","URL","document","require","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","result","toFixed","getModelInfo","ping","terminate","async","file","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","parseInt","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","level","plotType","plotDivId","meshType","yData","xData","from","lineData","mode","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","l","t","b","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString"],"mappings":"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"} \ No newline at end of file diff --git a/dist/feascript.esm.js b/dist/feascript.esm.js index 3c6355e..d0a9c3a 100644 --- a/dist/feascript.esm.js +++ b/dist/feascript.esm.js @@ -3,5 +3,5 @@ function e(e){let t=0;for(let n=0;n"object"==typeof e&&null!==e||"function"==typeof e,D=new Map([["proxy",{canHandle:e=>N(e)&&e[$],serialize(e){const{port1:t,port2:n}=new MessageChannel;return x(e,t),[n,[n]]},deserialize:e=>(e.start(),S(e))}],["throw",{canHandle:e=>N(e)&&w in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function x(e,t=globalThis,n=["*"]){t.addEventListener("message",(function s(o){if(!o||!o.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,o.origin))return void console.warn(`Invalid origin '${o.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},o.data),l=(o.data.argumentList||[]).map(W);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=W(o.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[$]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;x(e,n),d=function(e,t){return Y.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[w]:0}}Promise.resolve(d).catch((e=>({value:e,[w]:0}))).then((n=>{const[o,a]=R(n);t.postMessage(Object.assign(Object.assign({},o),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",s),O(t),C in e&&"function"==typeof e[C]&&e[C]())})).catch((e=>{const[n,s]=R({value:new TypeError("Unserializable return value"),[w]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),s)}))})),t.start&&t.start()}function O(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function S(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const s=n.get(t.id);if(s)try{s(t)}finally{n.delete(t.id)}})),T(e,n,[],t)}function A(e){if(e)throw new Error("Proxy has been released and is not useable")}function F(e){return B(e,new Map,{type:"RELEASE"}).then((()=>{O(e)}))}const X=new WeakMap,k="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(X.get(e)||0)-1;X.set(e,t),0===t&&F(e)}));function T(e,t,n=[],s=function(){}){let o=!1;const i=new Proxy(s,{get(s,r){if(A(o),r===v)return()=>{!function(e){k&&k.unregister(e)}(i),F(e),t.clear(),o=!0};if("then"===r){if(0===n.length)return{then:()=>i};const s=B(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(W);return s.then.bind(s)}return T(e,t,[...n,r])},set(s,i,r){A(o);const[a,l]=R(r);return B(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(W)},apply(s,i,r){A(o);const a=n[n.length-1];if(a===M)return B(e,t,{type:"ENDPOINT"}).then(W);if("bind"===a)return T(e,t,n.slice(0,-1));const[l,d]=P(r);return B(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(W)},construct(s,i){A(o);const[r,a]=P(i);return B(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(W)}});return function(e,t){const n=(X.get(t)||0)+1;X.set(t,n),k&&k.register(e,t,e)}(i,e),i}function P(e){const t=e.map(R);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const Y=new WeakMap;function R(e){for(const[t,n]of D)if(n.canHandle(e)){const[s,o]=n.serialize(e);return[{type:"HANDLER",name:t,value:s},o]}return[{type:"RAW",value:e},Y.get(e)||[]]}function W(e){switch(e.type){case"HANDLER":return D.get(e.name).deserialize(e.value);case"RAW":return e.value}}function B(e,t,n,s){return new Promise((o=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,o),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),s)}))}class I{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js",import.meta.url),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=S(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const s=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(s,1e3)};s()}))}async setSolverConfig(e){return await this._ensureReady(),o(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),o("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),o(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),o(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),o("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return o(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}}const q="0.1.2";export{y as FEAScriptModel,I as FEAScriptWorker,q as VERSION,b as importGmshQuadTri,n as logSystem,E as plotSolution,r as printVersion}; + */const $=Symbol("Comlink.proxy"),M=Symbol("Comlink.endpoint"),v=Symbol("Comlink.releaseProxy"),C=Symbol("Comlink.finalizer"),w=Symbol("Comlink.thrown"),N=e=>"object"==typeof e&&null!==e||"function"==typeof e,D=new Map([["proxy",{canHandle:e=>N(e)&&e[$],serialize(e){const{port1:t,port2:n}=new MessageChannel;return x(e,t),[n,[n]]},deserialize:e=>(e.start(),S(e))}],["throw",{canHandle:e=>N(e)&&w in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function x(e,t=globalThis,n=["*"]){t.addEventListener("message",(function s(o){if(!o||!o.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,o.origin))return void console.warn(`Invalid origin '${o.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},o.data),l=(o.data.argumentList||[]).map(W);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=W(o.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[$]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;x(e,n),d=function(e,t){return Y.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[w]:0}}Promise.resolve(d).catch((e=>({value:e,[w]:0}))).then((n=>{const[o,a]=R(n);t.postMessage(Object.assign(Object.assign({},o),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",s),O(t),C in e&&"function"==typeof e[C]&&e[C]())})).catch((e=>{const[n,s]=R({value:new TypeError("Unserializable return value"),[w]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),s)}))})),t.start&&t.start()}function O(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function S(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const s=n.get(t.id);if(s)try{s(t)}finally{n.delete(t.id)}})),T(e,n,[],t)}function A(e){if(e)throw new Error("Proxy has been released and is not useable")}function F(e){return B(e,new Map,{type:"RELEASE"}).then((()=>{O(e)}))}const X=new WeakMap,k="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(X.get(e)||0)-1;X.set(e,t),0===t&&F(e)}));function T(e,t,n=[],s=function(){}){let o=!1;const i=new Proxy(s,{get(s,r){if(A(o),r===v)return()=>{!function(e){k&&k.unregister(e)}(i),F(e),t.clear(),o=!0};if("then"===r){if(0===n.length)return{then:()=>i};const s=B(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(W);return s.then.bind(s)}return T(e,t,[...n,r])},set(s,i,r){A(o);const[a,l]=R(r);return B(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(W)},apply(s,i,r){A(o);const a=n[n.length-1];if(a===M)return B(e,t,{type:"ENDPOINT"}).then(W);if("bind"===a)return T(e,t,n.slice(0,-1));const[l,d]=P(r);return B(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(W)},construct(s,i){A(o);const[r,a]=P(i);return B(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(W)}});return function(e,t){const n=(X.get(t)||0)+1;X.set(t,n),k&&k.register(e,t,e)}(i,e),i}function P(e){const t=e.map(R);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const Y=new WeakMap;function R(e){for(const[t,n]of D)if(n.canHandle(e)){const[s,o]=n.serialize(e);return[{type:"HANDLER",name:t,value:s},o]}return[{type:"RAW",value:e},Y.get(e)||[]]}function W(e){switch(e.type){case"HANDLER":return D.get(e.name).deserialize(e.value);case"RAW":return e.value}}function B(e,t,n,s){return new Promise((o=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,o),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),s)}))}class I{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js",import.meta.url),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=S(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const s=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(s,1e3)};s()}))}async setSolverConfig(e){return await this._ensureReady(),o(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),o("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),o(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),o(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),o("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return o(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}}const q="0.1.3";export{y as FEAScriptModel,I as FEAScriptWorker,q as VERSION,b as importGmshQuadTri,n as logSystem,E as plotSolution,r as printVersion}; //# sourceMappingURL=feascript.esm.js.map diff --git a/dist/feascript.esm.js.map b/dist/feascript.esm.js.map index 4182a19..ac76e61 100644 --- a/dist/feascript.esm.js.map +++ b/dist/feascript.esm.js.map @@ -1 +1 @@ -{"version":3,"file":"feascript.esm.js","sources":["../src/methods/euclideanNormScript.js","../src/utilities/loggingScript.js","../src/methods/linearSystemScript.js","../src/methods/jacobiMethodScript.js","../src/methods/newtonRaphsonScript.js","../src/utilities/helperFunctionsScript.js","../src/solvers/genericBoundaryConditionsScript.js","../src/mesh/basisFunctionsScript.js","../src/mesh/meshGenerationScript.js","../src/methods/numericalIntegrationScript.js","../src/solvers/frontPropagationScript.js","../src/solvers/thermalBoundaryConditionsScript.js","../src/FEAScript.js","../src/solvers/solidHeatTransferScript.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.js","../src/vendor/comlink.mjs","../src/workers/workerScript.js","../src/index.js"],"sourcesContent":["// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to calculate the Euclidean norm of a vector\n * @param {array} vector - The input vector\n * @returns {number} The Euclidean norm of the vector\n */\nexport function euclideanNorm(vector) {\n let norm = 0;\n for (let i = 0; i < vector.length; i++) {\n norm += vector[i] * vector[i];\n }\n norm = Math.sqrt(norm);\n return norm;\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Global logging level\nlet currentLogLevel = \"basic\";\n\n/**\n * Function to set the logging system level\n * @param {string} level - Logging level (basic, debug)\n */\nexport function logSystem(level) {\n if (level !== \"basic\" && level !== \"debug\") {\n console.log(\n \"%c[WARN] Invalid log level: \" + level + \". Using basic instead.\",\n \"color: #FFC107; font-weight: bold;\"\n ); // Yellow for warnings\n currentLogLevel = \"basic\";\n } else {\n currentLogLevel = level;\n basicLog(`Log level set to: ${level}`);\n }\n}\n\n/**\n * Function to log debug messages - only logs if level is 'debug'\n * @param {string} message - Message to log\n */\nexport function debugLog(message) {\n if (currentLogLevel === \"debug\") {\n console.log(\"%c[DEBUG] \" + message, \"color: #2196F3; font-weight: bold;\"); // Blue color for debug\n }\n}\n\n/**\n * Function to log basic information - always logs\n * @param {string} message - Message to log\n */\nexport function basicLog(message) {\n console.log(\"%c[INFO] \" + message, \"color: #4CAF50; font-weight: bold;\"); // Green color for basic info\n}\n\n/**\n * Function to log error messages\n * @param {string} message - Message to log\n */\nexport function errorLog(message) {\n console.log(\"%c[ERROR] \" + message, \"color: #F44336; font-weight: bold;\"); // Red color for errors\n}\n\n/**\n * Function to handle version information and fetch the latest update date and release from GitHub\n */\nexport async function printVersion() {\n basicLog(\"Fetching latest FEAScript version information...\");\n try {\n const commitResponse = await fetch(\"https://api.github.com/repos/FEAScript/FEAScript/commits/main\");\n const commitData = await commitResponse.json();\n const latestCommitDate = new Date(commitData.commit.committer.date).toLocaleString();\n basicLog(`Latest FEAScript update: ${latestCommitDate}`);\n return latestCommitDate;\n } catch (error) {\n errorLog(\"Failed to fetch version information: \" + error);\n return \"Version information unavailable\";\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiMethod } from \"./jacobiMethodScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to solve a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (\"lusolve\" or \"jacobi\")\n * @param {Array} jacobianMatrix - The coefficient matrix\n * @param {Array} residualVector - The right-hand side vector\n * @param {object} [options] - Additional options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum iterations for iterative methods\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance for iterative methods\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - converged: Boolean indicating whether the method converged (for iterative methods)\n * - iterations: Number of iterations performed (for iterative methods)\n */\nexport function solveLinearSystem(solverMethod, jacobianMatrix, residualVector, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n\n let solutionVector = [];\n let converged = true;\n let iterations = 0;\n\n // Solve the linear system based on the specified solver method\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n if (solverMethod === \"lusolve\") {\n // Use LU decomposition method\n solutionVector = math.lusolve(jacobianMatrix, residualVector);\n } else if (solverMethod === \"jacobi\") {\n // Use Jacobi method\n const initialGuess = new Array(residualVector.length).fill(0);\n const jacobiResult = jacobiMethod(jacobianMatrix, residualVector, initialGuess, {\n maxIterations,\n tolerance,\n });\n\n // Log convergence information\n if (jacobiResult.converged) {\n debugLog(`Jacobi method converged in ${jacobiResult.iterations} iterations`);\n } else {\n debugLog(`Jacobi method did not converge after ${jacobiResult.iterations} iterations`);\n }\n\n solutionVector = jacobiResult.solutionVector;\n converged = jacobiResult.converged;\n iterations = jacobiResult.iterations;\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n return { solutionVector, converged, iterations };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method\n * @param {array} jacobianMatrix - The coefficient matrix (must be square)\n * @param {array} residualVector - The right-hand side vector\n * @param {array} initialGuess - Initial guess for solution vector\n * @param {object} [options] - Options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum number of iterations\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\nexport function jacobiMethod(jacobianMatrix, residualVector, initialGuess, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n const n = jacobianMatrix.length; // Size of the square matrix\n let x = [...initialGuess]; // Current solution (starts with initial guess)\n let xNew = new Array(n); // Next iteration's solution\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n // Perform one iteration\n for (let i = 0; i < n; i++) {\n let sum = 0;\n // Calculate sum of jacobianMatrix[i][j] * x[j] for j ≠ i\n for (let j = 0; j < n; j++) {\n if (j !== i) {\n sum += jacobianMatrix[i][j] * x[j];\n }\n }\n // Update xNew[i] using the Jacobi formula\n xNew[i] = (residualVector[i] - sum) / jacobianMatrix[i][i];\n }\n\n // Check convergence\n let maxDiff = 0;\n for (let i = 0; i < n; i++) {\n maxDiff = Math.max(maxDiff, Math.abs(xNew[i] - x[i]));\n }\n\n // Update x for next iteration\n x = [...xNew];\n\n // Successfully converged if maxDiff is less than tolerance\n if (maxDiff < tolerance) {\n return {\n solutionVector: x,\n iterations: iteration + 1,\n converged: true,\n };\n }\n }\n\n // maxIterations were reached without convergence\n return {\n solutionVector: x,\n iterations: maxIterations,\n converged: false,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { euclideanNorm } from \"../methods/euclideanNormScript.js\";\nimport { solveLinearSystem } from \"../methods/linearSystemScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\nimport { calculateSystemSize } from \"../utilities/helperFunctionsScript.js\";\n\n/**\n * Function to solve a system of nonlinear equations using the Newton-Raphson method\n * @param {number} [maxIterations=100] - Maximum number of iterations\n * @param {number} [tolerance=1e-4] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\n\nexport function newtonRaphson(assembleMat, context, maxIterations = 100, tolerance = 1e-4) {\n let errorNorm = 0;\n let converged = false;\n let iterations = 0;\n let deltaX = [];\n let solutionVector = [];\n let jacobianMatrix = [];\n let residualVector = [];\n let nodesCoordinates = {};\n\n // Calculate system size directly from meshConfig\n let totalNodes = calculateSystemSize(context.meshConfig);\n\n // Initialize arrays with proper size\n for (let i = 0; i < totalNodes; i++) {\n deltaX[i] = 0;\n solutionVector[i] = 0;\n }\n\n // Initialize solution from context if available\n if (context.initialSolution && context.initialSolution.length === totalNodes) {\n solutionVector = [...context.initialSolution];\n }\n\n while (iterations < maxIterations && !converged) {\n // Update solution\n for (let i = 0; i < solutionVector.length; i++) {\n solutionVector[i] = Number(solutionVector[i]) + Number(deltaX[i]);\n }\n\n // Compute Jacobian and residual matrices\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleMat(\n context.meshConfig,\n context.boundaryConditions,\n solutionVector, // The solution vector is required in the case of a non-linear equation\n context.eikonalActivationFlag\n ));\n\n // Solve the linear system based on the specified solver method\n const linearSystemResult = solveLinearSystem(context.solverMethod, jacobianMatrix, residualVector);\n deltaX = linearSystemResult.solutionVector;\n\n // Check convergence\n errorNorm = euclideanNorm(deltaX);\n\n // Norm for each iteration\n basicLog(`Newton-Raphson iteration ${iterations + 1}: Error norm = ${errorNorm.toExponential(4)}`);\n\n if (errorNorm <= tolerance) {\n converged = true;\n } else if (errorNorm > 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n nodesCoordinates,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Helper function to calculate system size from mesh configuration\n * @param {object} meshConfig - Mesh configuration object\n * @returns {number} Total number of nodes in the system\n */\nexport function calculateSystemSize(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, elementOrder, parsedMesh } = meshConfig;\n\n if (parsedMesh && parsedMesh.nodesXCoordinates) {\n // For parsed meshes (like from GMSH)\n return parsedMesh.nodesXCoordinates.length;\n } else {\n // For geometry-based meshes\n let nodesX,\n nodesY = 1;\n\n if (elementOrder === \"linear\") {\n nodesX = numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = numElementsY + 1;\n } else if (elementOrder === \"quadratic\") {\n nodesX = 2 * numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = 2 * numElementsY + 1;\n }\n\n return nodesX * nodesY;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n debugLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n if (\n this.numElementsX === null ||\n this.maxX === null ||\n this.numElementsY === null ||\n this.maxY === null\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n \n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\n\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the front propagation matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation (ranges from 0 to 1)\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleFrontPropagationMat(\n meshConfig,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n // TODO: The mesh generation step should be moved outside of the assembleFrontPropagationMat function so that not performed in every Newton-Raphson iteration\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n let solutionDerivX; // The x-derivative of the solution\n let solutionDerivY; // The y-derivative of the solution\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n detJacobian = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n detJacobian = ksiDerivX;\n }\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n // 2D front propagation (eikonal) equation\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n solutionDerivX = 0;\n solutionDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x & y-derivatives of basis functions and x & y-derivatives of the solution\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n // The x-derivative of the solution\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n // The y-derivative of the solution\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector - Viscous term: Add diffusion contribution to stabilize the solution\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n // residualVector - Eikonal term: Add the eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix - Viscous term: Add the Jacobian contribution from the diffusion term\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n // jacobianMatrix - Eikonal term: Add the Jacobian contribution from the eikonal equation\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n (detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)\n ) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n }\n\n // Create an instance of GenericBoundaryConditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions (Robin type)\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiMethod } from \"./methods/jacobiMethodScript.js\";\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n let nodesCoordinates = {};\n let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term - Used in frontPropagationScript\n let newtonRaphsonIterations;\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleSolidHeatTransferMat(\n this.meshConfig,\n this.boundaryConditions\n ));\n\n // Solve the assembled linear system\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n\n // Create context object with all necessary properties\n const context = {\n meshConfig: this.meshConfig,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n nodesCoordinates = newtonRaphsonResult.nodesCoordinates;\n solutionVector = newtonRaphsonResult.solutionVector;\n newtonRaphsonIterations = newtonRaphsonResult.iterations;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the solid heat transfer matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n // 2D solid heat transfer\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Create an instance of ThermalBoundaryConditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.2\";"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","logSystem","level","console","log","basicLog","debugLog","message","errorLog","async","printVersion","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString","error","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","math","lusolve","jacobiResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiMethod","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","nodesCoordinates","totalNodes","meshConfig","meshDimension","numElementsX","numElementsY","elementOrder","parsedMesh","nodesXCoordinates","nodesX","nodesY","calculateSystemSize","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","GenericBoundaryConditions","constructor","boundaryElements","nop","this","imposeConstantValueBoundaryConditions","Object","keys","forEach","boundaryKey","value","elementIndex","side","nodeIndex","globalNodeIndex","colIndex","BasisFunctions","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","maxX","maxY","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","undefined","fixedBoundaryElements","boundaryNodePairs","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","generate1DNodalNumbering","findBoundaryElements","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","assembleFrontPropagationMat","eikonalViscousTerm","mesh","nodesCoordinatesAndNumbering","totalElements","xCoordinates","yCoordinates","ksiDerivX","etaDerivX","ksiDerivY","etaDerivY","detJacobian","solutionDerivX","solutionDerivY","localToGlobalMap","basisFunctionDerivX","basisFunctionDerivY","basisFunctions","gaussPointsAndWeights","numNodes","localNodeIndex","gaussPointIndex1","basisFunctionsAndDerivatives","gaussPointIndex2","localNodeIndex1","localToGlobalMap1","localNodeIndex2","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","FEAScriptModel","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","Error","thermalBoundaryConditions","assembleSolidHeatTransferMat","newtonRaphsonResult","importGmshQuadTri","file","result","gmshV","ascii","fltBytes","lines","text","split","map","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","test","parseInt","slice","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","plotSolution","plotType","plotDivId","meshType","yData","arr","xData","from","lineData","mode","type","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","l","r","t","b","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","val","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","isAllowedOrigin","warn","id","path","argumentList","fromWireValue","returnValue","parent","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","FEAScriptWorker","worker","feaWorker","isReady","_initWorker","Worker","URL","url","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","toFixed","getModelInfo","ping","terminate","VERSION"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"feascript.esm.js","sources":["../src/methods/euclideanNormScript.js","../src/utilities/loggingScript.js","../src/methods/linearSystemSolverScript.js","../src/methods/jacobiSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/utilities/helperFunctionsScript.js","../src/solvers/genericBoundaryConditionsScript.js","../src/mesh/basisFunctionsScript.js","../src/mesh/meshGenerationScript.js","../src/methods/numericalIntegrationScript.js","../src/solvers/frontPropagationScript.js","../src/solvers/thermalBoundaryConditionsScript.js","../src/FEAScript.js","../src/solvers/solidHeatTransferScript.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.js","../src/vendor/comlink.mjs","../src/workers/workerScript.js","../src/index.js"],"sourcesContent":["// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to calculate the Euclidean norm of a vector\n * @param {array} vector - The input vector\n * @returns {number} The Euclidean norm of the vector\n */\nexport function euclideanNorm(vector) {\n let norm = 0;\n for (let i = 0; i < vector.length; i++) {\n norm += vector[i] * vector[i];\n }\n norm = Math.sqrt(norm);\n return norm;\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Global logging level\nlet currentLogLevel = \"basic\";\n\n/**\n * Function to set the logging system level\n * @param {string} level - Logging level (basic, debug)\n */\nexport function logSystem(level) {\n if (level !== \"basic\" && level !== \"debug\") {\n console.log(\n \"%c[WARN] Invalid log level: \" + level + \". Using basic instead.\",\n \"color: #FFC107; font-weight: bold;\"\n ); // Yellow for warnings\n currentLogLevel = \"basic\";\n } else {\n currentLogLevel = level;\n basicLog(`Log level set to: ${level}`);\n }\n}\n\n/**\n * Function to log debug messages - only logs if level is 'debug'\n * @param {string} message - Message to log\n */\nexport function debugLog(message) {\n if (currentLogLevel === \"debug\") {\n console.log(\"%c[DEBUG] \" + message, \"color: #2196F3; font-weight: bold;\"); // Blue color for debug\n }\n}\n\n/**\n * Function to log basic information - always logs\n * @param {string} message - Message to log\n */\nexport function basicLog(message) {\n console.log(\"%c[INFO] \" + message, \"color: #4CAF50; font-weight: bold;\"); // Green color for basic info\n}\n\n/**\n * Function to log error messages\n * @param {string} message - Message to log\n */\nexport function errorLog(message) {\n console.log(\"%c[ERROR] \" + message, \"color: #F44336; font-weight: bold;\"); // Red color for errors\n}\n\n/**\n * Function to handle version information and fetch the latest update date and release from GitHub\n */\nexport async function printVersion() {\n basicLog(\"Fetching latest FEAScript version information...\");\n try {\n const commitResponse = await fetch(\"https://api.github.com/repos/FEAScript/FEAScript/commits/main\");\n const commitData = await commitResponse.json();\n const latestCommitDate = new Date(commitData.commit.committer.date).toLocaleString();\n basicLog(`Latest FEAScript update: ${latestCommitDate}`);\n return latestCommitDate;\n } catch (error) {\n errorLog(\"Failed to fetch version information: \" + error);\n return \"Version information unavailable\";\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiSolver } from \"./jacobiSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to solve a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (\"lusolve\" or \"jacobi\")\n * @param {Array} jacobianMatrix - The coefficient matrix\n * @param {Array} residualVector - The right-hand side vector\n * @param {object} [options] - Additional options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum iterations for iterative methods\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance for iterative methods\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - converged: Boolean indicating whether the method converged (for iterative methods)\n * - iterations: Number of iterations performed (for iterative methods)\n */\nexport function solveLinearSystem(solverMethod, jacobianMatrix, residualVector, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n\n let solutionVector = [];\n let converged = true;\n let iterations = 0;\n\n // Solve the linear system based on the specified solver method\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n if (solverMethod === \"lusolve\") {\n // Use LU decomposition method\n solutionVector = math.lusolve(jacobianMatrix, residualVector);\n } else if (solverMethod === \"jacobi\") {\n // Use Jacobi method\n const initialGuess = new Array(residualVector.length).fill(0);\n const jacobiSolverResult = jacobiSolver(jacobianMatrix, residualVector, initialGuess, {\n maxIterations,\n tolerance,\n });\n\n // Log convergence information\n if (jacobiSolverResult.converged) {\n debugLog(`Jacobi method converged in ${jacobiSolverResult.iterations} iterations`);\n } else {\n debugLog(`Jacobi method did not converge after ${jacobiSolverResult.iterations} iterations`);\n }\n\n solutionVector = jacobiSolverResult.solutionVector;\n converged = jacobiSolverResult.converged;\n iterations = jacobiSolverResult.iterations;\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n return { solutionVector, converged, iterations };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method\n * @param {array} jacobianMatrix - The coefficient matrix (must be square)\n * @param {array} residualVector - The right-hand side vector\n * @param {array} initialGuess - Initial guess for solution vector\n * @param {object} [options] - Options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum number of iterations\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\nexport function jacobiSolver(jacobianMatrix, residualVector, initialGuess, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n const n = jacobianMatrix.length; // Size of the square matrix\n let x = [...initialGuess]; // Current solution (starts with initial guess)\n let xNew = new Array(n); // Next iteration's solution\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n // Perform one iteration\n for (let i = 0; i < n; i++) {\n let sum = 0;\n // Calculate sum of jacobianMatrix[i][j] * x[j] for j ≠ i\n for (let j = 0; j < n; j++) {\n if (j !== i) {\n sum += jacobianMatrix[i][j] * x[j];\n }\n }\n // Update xNew[i] using the Jacobi formula\n xNew[i] = (residualVector[i] - sum) / jacobianMatrix[i][i];\n }\n\n // Check convergence\n let maxDiff = 0;\n for (let i = 0; i < n; i++) {\n maxDiff = Math.max(maxDiff, Math.abs(xNew[i] - x[i]));\n }\n\n // Update x for next iteration\n x = [...xNew];\n\n // Successfully converged if maxDiff is less than tolerance\n if (maxDiff < tolerance) {\n return {\n solutionVector: x,\n iterations: iteration + 1,\n converged: true,\n };\n }\n }\n\n // maxIterations were reached without convergence\n return {\n solutionVector: x,\n iterations: maxIterations,\n converged: false,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { euclideanNorm } from \"../methods/euclideanNormScript.js\";\nimport { solveLinearSystem } from \"./linearSystemSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\nimport { calculateSystemSize } from \"../utilities/helperFunctionsScript.js\";\n\n/**\n * Function to solve a system of nonlinear equations using the Newton-Raphson method\n * @param {number} [maxIterations=100] - Maximum number of iterations\n * @param {number} [tolerance=1e-4] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\n\nexport function newtonRaphson(assembleMat, context, maxIterations = 100, tolerance = 1e-4) {\n let errorNorm = 0;\n let converged = false;\n let iterations = 0;\n let deltaX = [];\n let solutionVector = [];\n let jacobianMatrix = [];\n let residualVector = [];\n let nodesCoordinates = {};\n\n // Calculate system size directly from meshConfig\n let totalNodes = calculateSystemSize(context.meshConfig);\n\n // Initialize arrays with proper size\n for (let i = 0; i < totalNodes; i++) {\n deltaX[i] = 0;\n solutionVector[i] = 0;\n }\n\n // Initialize solution from context if available\n if (context.initialSolution && context.initialSolution.length === totalNodes) {\n solutionVector = [...context.initialSolution];\n }\n\n while (iterations < maxIterations && !converged) {\n // Update solution\n for (let i = 0; i < solutionVector.length; i++) {\n solutionVector[i] = Number(solutionVector[i]) + Number(deltaX[i]);\n }\n\n // Compute Jacobian and residual matrices\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleMat(\n context.meshConfig,\n context.boundaryConditions,\n solutionVector, // The solution vector is required in the case of a non-linear equation\n context.eikonalActivationFlag\n ));\n\n // Solve the linear system based on the specified solver method\n const linearSystemResult = solveLinearSystem(context.solverMethod, jacobianMatrix, residualVector);\n deltaX = linearSystemResult.solutionVector;\n\n // Check convergence\n errorNorm = euclideanNorm(deltaX);\n\n // Norm for each iteration\n basicLog(`Newton-Raphson iteration ${iterations + 1}: Error norm = ${errorNorm.toExponential(4)}`);\n\n if (errorNorm <= tolerance) {\n converged = true;\n } else if (errorNorm > 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n nodesCoordinates,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Helper function to calculate system size from mesh configuration\n * @param {object} meshConfig - Mesh configuration object\n * @returns {number} Total number of nodes in the system\n */\nexport function calculateSystemSize(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, elementOrder, parsedMesh } = meshConfig;\n\n if (parsedMesh && parsedMesh.nodesXCoordinates) {\n // For parsed meshes (like from GMSH)\n return parsedMesh.nodesXCoordinates.length;\n } else {\n // For geometry-based meshes\n let nodesX,\n nodesY = 1;\n\n if (elementOrder === \"linear\") {\n nodesX = numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = numElementsY + 1;\n } else if (elementOrder === \"quadratic\") {\n nodesX = 2 * numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = 2 * numElementsY + 1;\n }\n\n return nodesX * nodesY;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n debugLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n if (\n this.numElementsX === null ||\n this.maxX === null ||\n this.numElementsY === null ||\n this.maxY === null\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n \n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\n\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the front propagation matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation (ranges from 0 to 1)\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleFrontPropagationMat(\n meshConfig,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n // TODO: The mesh generation step should be moved outside of the assembleFrontPropagationMat function so that not performed in every Newton-Raphson iteration\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n let solutionDerivX; // The x-derivative of the solution\n let solutionDerivY; // The y-derivative of the solution\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n detJacobian = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n detJacobian = ksiDerivX;\n }\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n // 2D front propagation (eikonal) equation\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n solutionDerivX = 0;\n solutionDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x & y-derivatives of basis functions and x & y-derivatives of the solution\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n // The x-derivative of the solution\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n // The y-derivative of the solution\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector - Viscous term: Add diffusion contribution to stabilize the solution\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n // residualVector - Eikonal term: Add the eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix - Viscous term: Add the Jacobian contribution from the diffusion term\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n // jacobianMatrix - Eikonal term: Add the Jacobian contribution from the eikonal equation\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n (detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)\n ) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n }\n\n // Create an instance of GenericBoundaryConditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions (Robin type)\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n let nodesCoordinates = {};\n let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term - Used in frontPropagationScript\n let newtonRaphsonIterations;\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleSolidHeatTransferMat(\n this.meshConfig,\n this.boundaryConditions\n ));\n\n // Solve the assembled linear system\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n\n // Create context object with all necessary properties\n const context = {\n meshConfig: this.meshConfig,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n nodesCoordinates = newtonRaphsonResult.nodesCoordinates;\n solutionVector = newtonRaphsonResult.solutionVector;\n newtonRaphsonIterations = newtonRaphsonResult.iterations;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the solid heat transfer matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n // 2D solid heat transfer\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Create an instance of ThermalBoundaryConditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.3\";"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","logSystem","level","console","log","basicLog","debugLog","message","errorLog","async","printVersion","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString","error","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","math","lusolve","jacobiSolverResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiSolver","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","nodesCoordinates","totalNodes","meshConfig","meshDimension","numElementsX","numElementsY","elementOrder","parsedMesh","nodesXCoordinates","nodesX","nodesY","calculateSystemSize","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","GenericBoundaryConditions","constructor","boundaryElements","nop","this","imposeConstantValueBoundaryConditions","Object","keys","forEach","boundaryKey","value","elementIndex","side","nodeIndex","globalNodeIndex","colIndex","BasisFunctions","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","maxX","maxY","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","undefined","fixedBoundaryElements","boundaryNodePairs","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","generate1DNodalNumbering","findBoundaryElements","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","assembleFrontPropagationMat","eikonalViscousTerm","mesh","nodesCoordinatesAndNumbering","totalElements","xCoordinates","yCoordinates","ksiDerivX","etaDerivX","ksiDerivY","etaDerivY","detJacobian","solutionDerivX","solutionDerivY","localToGlobalMap","basisFunctionDerivX","basisFunctionDerivY","basisFunctions","gaussPointsAndWeights","numNodes","localNodeIndex","gaussPointIndex1","basisFunctionsAndDerivatives","gaussPointIndex2","localNodeIndex1","localToGlobalMap1","localNodeIndex2","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","FEAScriptModel","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","Error","thermalBoundaryConditions","assembleSolidHeatTransferMat","newtonRaphsonResult","importGmshQuadTri","file","result","gmshV","ascii","fltBytes","lines","text","split","map","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","test","parseInt","slice","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","plotSolution","plotType","plotDivId","meshType","yData","arr","xData","from","lineData","mode","type","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","l","r","t","b","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","val","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","isAllowedOrigin","warn","id","path","argumentList","fromWireValue","returnValue","parent","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","FEAScriptWorker","worker","feaWorker","isReady","_initWorker","Worker","URL","url","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","toFixed","getModelInfo","ping","terminate","VERSION"],"mappings":"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"} \ No newline at end of file diff --git a/dist/feascript.umd.js b/dist/feascript.umd.js index dc4058b..3af0cfe 100644 --- a/dist/feascript.umd.js +++ b/dist/feascript.umd.js @@ -4,5 +4,5 @@ * Copyright 2019 Google LLC * SPDX-License-Identifier: Apache-2.0 */ -const g=Symbol("Comlink.proxy"),y=Symbol("Comlink.endpoint"),b=Symbol("Comlink.releaseProxy"),E=Symbol("Comlink.finalizer"),$=Symbol("Comlink.thrown"),M=e=>"object"==typeof e&&null!==e||"function"==typeof e,v=new Map([["proxy",{canHandle:e=>M(e)&&e[g],serialize(e){const{port1:t,port2:n}=new MessageChannel;return C(e,t),[n,[n]]},deserialize:e=>(e.start(),S(e))}],["throw",{canHandle:e=>M(e)&&$ in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function C(e,t=globalThis,n=["*"]){t.addEventListener("message",(function o(s){if(!s||!s.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,s.origin))return void console.warn(`Invalid origin '${s.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},s.data),l=(s.data.argumentList||[]).map(T);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=T(s.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[g]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;C(e,n),d=function(e,t){return X.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[$]:0}}Promise.resolve(d).catch((e=>({value:e,[$]:0}))).then((n=>{const[s,a]=k(n);t.postMessage(Object.assign(Object.assign({},s),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",o),w(t),E in e&&"function"==typeof e[E]&&e[E]())})).catch((e=>{const[n,o]=k({value:new TypeError("Unserializable return value"),[$]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),o)}))})),t.start&&t.start()}function w(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function S(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const o=n.get(t.id);if(o)try{o(t)}finally{n.delete(t.id)}})),A(e,n,[],t)}function N(e){if(e)throw new Error("Proxy has been released and is not useable")}function x(e){return P(e,new Map,{type:"RELEASE"}).then((()=>{w(e)}))}const O=new WeakMap,D="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(O.get(e)||0)-1;O.set(e,t),0===t&&x(e)}));function A(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(N(s),r===b)return()=>{!function(e){D&&D.unregister(e)}(i),x(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=P(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(T);return o.then.bind(o)}return A(e,t,[...n,r])},set(o,i,r){N(s);const[a,l]=k(r);return P(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(T)},apply(o,i,r){N(s);const a=n[n.length-1];if(a===y)return P(e,t,{type:"ENDPOINT"}).then(T);if("bind"===a)return A(e,t,n.slice(0,-1));const[l,d]=F(r);return P(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(T)},construct(o,i){N(s);const[r,a]=F(i);return P(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(T)}});return function(e,t){const n=(O.get(t)||0)+1;O.set(t,n),D&&D.register(e,t,e)}(i,e),i}function F(e){const t=e.map(k);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const X=new WeakMap;function k(e){for(const[t,n]of v)if(n.canHandle(e)){const[o,s]=n.serialize(e);return[{type:"HANDLER",name:t,value:o},s]}return[{type:"RAW",value:e},X.get(e)||[]]}function T(e){switch(e.type){case"HANDLER":return v.get(e.name).deserialize(e.value);case"RAW":return e.value}}function P(e,t,n,o){return new Promise((s=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,s),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),o)}))}e.FEAScriptModel=class{constructor(){this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",s("FEAScriptModel instance created")}setSolverConfig(e){this.solverConfig=e,o(`Solver config set to: ${e}`)}setMeshConfig(e){this.meshConfig=e,o(`Mesh config set with dimensions: ${e.meshDimension}`)}addBoundaryCondition(e,t){this.boundaryConditions[e]=t,o(`Boundary condition added for boundary: ${e}, type: ${t[0]}`)}setSolverMethod(e){this.solverMethod=e,o(`Solver method set to: ${e}`)}solve(){if(!this.solverConfig||!this.meshConfig||!this.boundaryConditions){const e="Solver config, mesh config, and boundary conditions must be set before solving.";throw console.error(e),new Error(e)}let e=[],t=[],n=[],l=[],m={};if(s("Beginning solving process..."),console.time("totalSolvingTime"),"solidHeatTransferScript"===this.solverConfig){s(`Using solver: ${this.solverConfig}`),({jacobianMatrix:e,residualVector:t,nodesCoordinates:m}=function(e,t){s("Starting solid heat transfer matrix assembly...");const{meshDimension:n,numElementsX:r,numElementsY:a,maxX:l,maxY:m,elementOrder:f,parsedMesh:g}=e;let y;o("Generating mesh..."),"1D"===n?y=new h({numElementsX:r,maxX:l,elementOrder:f,parsedMesh:g}):"2D"===n?y=new u({numElementsX:r,maxX:l,numElementsY:a,maxY:m,elementOrder:f,parsedMesh:g}):i("Mesh dimension must be either '1D' or '2D'.");const b=y.boundaryElementsProcessed?y.parsedMesh:y.generateMesh();let E,$,M=b.nodesXCoordinates,v=b.nodesYCoordinates,C=b.totalNodesX,w=b.totalNodesY,S=b.nodalNumbering,N=b.boundaryElements;null!=g?(E=S.length,$=M.length,o(`Using parsed mesh with ${E} elements and ${$} nodes`)):(E=r*("2D"===n?a:1),$=C*("2D"===n?w:1),o(`Using mesh generated from geometry with ${E} elements and ${$} nodes`));let x,O,D,A,F,X,k,T=[],P=[],Y=[],R=[],W=[],I=[],B=[],j=[],q=[],V=[];for(let e=0;e<$;e++){q[e]=0,V.push([]);for(let t=0;t<$;t++)V[e][t]=0}const L=new d({meshDimension:n,elementOrder:f});let G=new c({meshDimension:n,elementOrder:f}).getGaussPointsAndWeights();P=G.gaussPoints,Y=G.gaussWeights;const U=S[0].length;for(let e=0;e0&&(i.initialSolution=[...n]);const s=a(f,i,100,1e-4);e=s.jacobianMatrix,t=s.residualVector,m=s.nodesCoordinates,n=s.solutionVector,o+=.2}}return console.timeEnd("totalSolvingTime"),s("Solving process completed"),{solutionVector:n,nodesCoordinates:m}}},e.FEAScriptWorker=class{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js","undefined"==typeof document&&"undefined"==typeof location?new(require("url").URL)("file:"+__filename).href:"undefined"==typeof document?location.href:document.currentScript&&"SCRIPT"===document.currentScript.tagName.toUpperCase()&&document.currentScript.src||new URL("feascript.umd.js",document.baseURI).href),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=S(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const o=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(o,1e3)};o()}))}async setSolverConfig(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),s("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),s(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),s("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return s(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}},e.VERSION="0.1.2",e.importGmshQuadTri=async e=>{let t={nodesXCoordinates:[],nodesYCoordinates:[],nodalNumbering:{quadElements:[],triangleElements:[]},boundaryElements:[],boundaryConditions:[],boundaryNodePairs:{},gmshV:0,ascii:!1,fltBytes:"8",totalNodesX:0,totalNodesY:0,physicalPropMap:[],elementTypes:{}},n=(await e.text()).split("\n").map((e=>e.trim())).filter((e=>""!==e&&" "!==e)),s="",i=0,r=0,a=0,l=0,d={numNodes:0},m=0,h=[],u=0,c=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},g=0,y={};for(;i""!==e));if("meshFormat"===s)t.gmshV=parseFloat(o[0]),t.ascii="0"===o[1],t.fltBytes=o[2];else if("physicalNames"===s){if(o.length>=3){if(!/^\d+$/.test(o[0])){i++;continue}const e=parseInt(o[0],10),n=parseInt(o[1],10);let s=o.slice(2).join(" ");s=s.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:n,dimension:e,name:s})}}else if("nodes"===s){if(0===r){r=parseInt(o[0],10),a=parseInt(o[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;y[n]||(y[n]=[]),y[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);g++,g===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=y[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),o(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t},e.logSystem=function(e){"basic"!==e&&"debug"!==e?(console.log("%c[WARN] Invalid log level: "+e+". Using basic instead.","color: #FFC107; font-weight: bold;"),n="basic"):(n=e,s(`Log level set to: ${e}`))},e.plotSolution=function(e,t,n,o,s,i,r="structured"){const{nodesXCoordinates:a,nodesYCoordinates:l}=t;if("1D"===o&&"line"===s){let t;t=e.length>0&&Array.isArray(e[0])?e.map((e=>e[0])):e;let o=Array.from(a),s={x:o,y:t,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},r=Math.min(window.innerWidth,700),l=Math.max(...o),d=r/l,m={title:`line plot - ${n}`,width:Math.max(d*l,400),height:350,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:70,r:40,t:50,b:50}};Plotly.newPlot(i,[s],m,{responsive:!0})}else if("2D"===o&&"contour"===s){const t="structured"===r,o=new Set(a).size,d=new Set(l).size;let m;m=Array.isArray(e[0])?e.map((e=>e[0])):e;let h=Math.min(window.innerWidth,700),u=Math.max(...a),c=Math.max(...l)/u,f=Math.min(h,600),p={title:`${s} plot - ${n}`,width:f,height:f*c*.8,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"};if(t){const t=o,n=d;math.reshape(Array.from(a),[t,n]);let s=math.reshape(Array.from(l),[t,n]),r=math.reshape(Array.from(e),[t,n]),m=math.transpose(r),h=[];for(let e=0;e"object"==typeof e&&null!==e||"function"==typeof e,v=new Map([["proxy",{canHandle:e=>M(e)&&e[g],serialize(e){const{port1:t,port2:n}=new MessageChannel;return C(e,t),[n,[n]]},deserialize:e=>(e.start(),S(e))}],["throw",{canHandle:e=>M(e)&&$ in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function C(e,t=globalThis,n=["*"]){t.addEventListener("message",(function o(s){if(!s||!s.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,s.origin))return void console.warn(`Invalid origin '${s.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},s.data),l=(s.data.argumentList||[]).map(T);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=T(s.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[g]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;C(e,n),d=function(e,t){return X.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[$]:0}}Promise.resolve(d).catch((e=>({value:e,[$]:0}))).then((n=>{const[s,a]=k(n);t.postMessage(Object.assign(Object.assign({},s),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",o),w(t),E in e&&"function"==typeof e[E]&&e[E]())})).catch((e=>{const[n,o]=k({value:new TypeError("Unserializable return value"),[$]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),o)}))})),t.start&&t.start()}function w(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function S(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const o=n.get(t.id);if(o)try{o(t)}finally{n.delete(t.id)}})),A(e,n,[],t)}function N(e){if(e)throw new Error("Proxy has been released and is not useable")}function x(e){return P(e,new Map,{type:"RELEASE"}).then((()=>{w(e)}))}const O=new WeakMap,D="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(O.get(e)||0)-1;O.set(e,t),0===t&&x(e)}));function A(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(N(s),r===b)return()=>{!function(e){D&&D.unregister(e)}(i),x(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=P(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(T);return o.then.bind(o)}return A(e,t,[...n,r])},set(o,i,r){N(s);const[a,l]=k(r);return P(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(T)},apply(o,i,r){N(s);const a=n[n.length-1];if(a===y)return P(e,t,{type:"ENDPOINT"}).then(T);if("bind"===a)return A(e,t,n.slice(0,-1));const[l,d]=F(r);return P(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(T)},construct(o,i){N(s);const[r,a]=F(i);return P(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(T)}});return function(e,t){const n=(O.get(t)||0)+1;O.set(t,n),D&&D.register(e,t,e)}(i,e),i}function F(e){const t=e.map(k);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const X=new WeakMap;function k(e){for(const[t,n]of v)if(n.canHandle(e)){const[o,s]=n.serialize(e);return[{type:"HANDLER",name:t,value:o},s]}return[{type:"RAW",value:e},X.get(e)||[]]}function T(e){switch(e.type){case"HANDLER":return v.get(e.name).deserialize(e.value);case"RAW":return e.value}}function P(e,t,n,o){return new Promise((s=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,s),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),o)}))}e.FEAScriptModel=class{constructor(){this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",s("FEAScriptModel instance created")}setSolverConfig(e){this.solverConfig=e,o(`Solver config set to: ${e}`)}setMeshConfig(e){this.meshConfig=e,o(`Mesh config set with dimensions: ${e.meshDimension}`)}addBoundaryCondition(e,t){this.boundaryConditions[e]=t,o(`Boundary condition added for boundary: ${e}, type: ${t[0]}`)}setSolverMethod(e){this.solverMethod=e,o(`Solver method set to: ${e}`)}solve(){if(!this.solverConfig||!this.meshConfig||!this.boundaryConditions){const e="Solver config, mesh config, and boundary conditions must be set before solving.";throw console.error(e),new Error(e)}let e=[],t=[],n=[],l=[],m={};if(s("Beginning solving process..."),console.time("totalSolvingTime"),"solidHeatTransferScript"===this.solverConfig){s(`Using solver: ${this.solverConfig}`),({jacobianMatrix:e,residualVector:t,nodesCoordinates:m}=function(e,t){s("Starting solid heat transfer matrix assembly...");const{meshDimension:n,numElementsX:r,numElementsY:a,maxX:l,maxY:m,elementOrder:f,parsedMesh:g}=e;let y;o("Generating mesh..."),"1D"===n?y=new h({numElementsX:r,maxX:l,elementOrder:f,parsedMesh:g}):"2D"===n?y=new u({numElementsX:r,maxX:l,numElementsY:a,maxY:m,elementOrder:f,parsedMesh:g}):i("Mesh dimension must be either '1D' or '2D'.");const b=y.boundaryElementsProcessed?y.parsedMesh:y.generateMesh();let E,$,M=b.nodesXCoordinates,v=b.nodesYCoordinates,C=b.totalNodesX,w=b.totalNodesY,S=b.nodalNumbering,N=b.boundaryElements;null!=g?(E=S.length,$=M.length,o(`Using parsed mesh with ${E} elements and ${$} nodes`)):(E=r*("2D"===n?a:1),$=C*("2D"===n?w:1),o(`Using mesh generated from geometry with ${E} elements and ${$} nodes`));let x,O,D,A,F,X,k,T=[],P=[],Y=[],R=[],W=[],I=[],B=[],j=[],q=[],V=[];for(let e=0;e<$;e++){q[e]=0,V.push([]);for(let t=0;t<$;t++)V[e][t]=0}const L=new d({meshDimension:n,elementOrder:f});let G=new c({meshDimension:n,elementOrder:f}).getGaussPointsAndWeights();P=G.gaussPoints,Y=G.gaussWeights;const U=S[0].length;for(let e=0;e0&&(i.initialSolution=[...n]);const s=a(f,i,100,1e-4);e=s.jacobianMatrix,t=s.residualVector,m=s.nodesCoordinates,n=s.solutionVector,o+=.2}}return console.timeEnd("totalSolvingTime"),s("Solving process completed"),{solutionVector:n,nodesCoordinates:m}}},e.FEAScriptWorker=class{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js","undefined"==typeof document&&"undefined"==typeof location?new(require("url").URL)("file:"+__filename).href:"undefined"==typeof document?location.href:document.currentScript&&"SCRIPT"===document.currentScript.tagName.toUpperCase()&&document.currentScript.src||new URL("feascript.umd.js",document.baseURI).href),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=S(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const o=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(o,1e3)};o()}))}async setSolverConfig(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),s("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),s(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),s("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return s(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}},e.VERSION="0.1.3",e.importGmshQuadTri=async e=>{let t={nodesXCoordinates:[],nodesYCoordinates:[],nodalNumbering:{quadElements:[],triangleElements:[]},boundaryElements:[],boundaryConditions:[],boundaryNodePairs:{},gmshV:0,ascii:!1,fltBytes:"8",totalNodesX:0,totalNodesY:0,physicalPropMap:[],elementTypes:{}},n=(await e.text()).split("\n").map((e=>e.trim())).filter((e=>""!==e&&" "!==e)),s="",i=0,r=0,a=0,l=0,d={numNodes:0},m=0,h=[],u=0,c=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},g=0,y={};for(;i""!==e));if("meshFormat"===s)t.gmshV=parseFloat(o[0]),t.ascii="0"===o[1],t.fltBytes=o[2];else if("physicalNames"===s){if(o.length>=3){if(!/^\d+$/.test(o[0])){i++;continue}const e=parseInt(o[0],10),n=parseInt(o[1],10);let s=o.slice(2).join(" ");s=s.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:n,dimension:e,name:s})}}else if("nodes"===s){if(0===r){r=parseInt(o[0],10),a=parseInt(o[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;y[n]||(y[n]=[]),y[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);g++,g===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=y[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),o(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t},e.logSystem=function(e){"basic"!==e&&"debug"!==e?(console.log("%c[WARN] Invalid log level: "+e+". Using basic instead.","color: #FFC107; font-weight: bold;"),n="basic"):(n=e,s(`Log level set to: ${e}`))},e.plotSolution=function(e,t,n,o,s,i,r="structured"){const{nodesXCoordinates:a,nodesYCoordinates:l}=t;if("1D"===o&&"line"===s){let t;t=e.length>0&&Array.isArray(e[0])?e.map((e=>e[0])):e;let o=Array.from(a),s={x:o,y:t,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},r=Math.min(window.innerWidth,700),l=Math.max(...o),d=r/l,m={title:`line plot - ${n}`,width:Math.max(d*l,400),height:350,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:70,r:40,t:50,b:50}};Plotly.newPlot(i,[s],m,{responsive:!0})}else if("2D"===o&&"contour"===s){const t="structured"===r,o=new Set(a).size,d=new Set(l).size;let m;m=Array.isArray(e[0])?e.map((e=>e[0])):e;let h=Math.min(window.innerWidth,700),u=Math.max(...a),c=Math.max(...l)/u,f=Math.min(h,600),p={title:`${s} plot - ${n}`,width:f,height:f*c*.8,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"};if(t){const t=o,n=d;math.reshape(Array.from(a),[t,n]);let s=math.reshape(Array.from(l),[t,n]),r=math.reshape(Array.from(e),[t,n]),m=math.transpose(r),h=[];for(let e=0;e 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n nodesCoordinates,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Helper function to calculate system size from mesh configuration\n * @param {object} meshConfig - Mesh configuration object\n * @returns {number} Total number of nodes in the system\n */\nexport function calculateSystemSize(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, elementOrder, parsedMesh } = meshConfig;\n\n if (parsedMesh && parsedMesh.nodesXCoordinates) {\n // For parsed meshes (like from GMSH)\n return parsedMesh.nodesXCoordinates.length;\n } else {\n // For geometry-based meshes\n let nodesX,\n nodesY = 1;\n\n if (elementOrder === \"linear\") {\n nodesX = numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = numElementsY + 1;\n } else if (elementOrder === \"quadratic\") {\n nodesX = 2 * numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = 2 * numElementsY + 1;\n }\n\n return nodesX * nodesY;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n debugLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n if (\n this.numElementsX === null ||\n this.maxX === null ||\n this.numElementsY === null ||\n this.maxY === null\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n \n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\n\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the front propagation matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation (ranges from 0 to 1)\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleFrontPropagationMat(\n meshConfig,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n // TODO: The mesh generation step should be moved outside of the assembleFrontPropagationMat function so that not performed in every Newton-Raphson iteration\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n let solutionDerivX; // The x-derivative of the solution\n let solutionDerivY; // The y-derivative of the solution\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n detJacobian = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n detJacobian = ksiDerivX;\n }\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n // 2D front propagation (eikonal) equation\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n solutionDerivX = 0;\n solutionDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x & y-derivatives of basis functions and x & y-derivatives of the solution\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n // The x-derivative of the solution\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n // The y-derivative of the solution\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector - Viscous term: Add diffusion contribution to stabilize the solution\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n // residualVector - Eikonal term: Add the eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix - Viscous term: Add the Jacobian contribution from the diffusion term\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n // jacobianMatrix - Eikonal term: Add the Jacobian contribution from the eikonal equation\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n (detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)\n ) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n }\n\n // Create an instance of GenericBoundaryConditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions (Robin type)\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiMethod } from \"./methods/jacobiMethodScript.js\";\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n let nodesCoordinates = {};\n let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term - Used in frontPropagationScript\n let newtonRaphsonIterations;\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleSolidHeatTransferMat(\n this.meshConfig,\n this.boundaryConditions\n ));\n\n // Solve the assembled linear system\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n\n // Create context object with all necessary properties\n const context = {\n meshConfig: this.meshConfig,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n nodesCoordinates = newtonRaphsonResult.nodesCoordinates;\n solutionVector = newtonRaphsonResult.solutionVector;\n newtonRaphsonIterations = newtonRaphsonResult.iterations;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the solid heat transfer matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n // 2D solid heat transfer\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Create an instance of ThermalBoundaryConditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.2\";","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","debugLog","message","console","log","basicLog","errorLog","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","math","lusolve","jacobiResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiMethod","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","nodesCoordinates","totalNodes","meshConfig","meshDimension","numElementsX","numElementsY","elementOrder","parsedMesh","nodesXCoordinates","nodesX","nodesY","calculateSystemSize","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","GenericBoundaryConditions","constructor","boundaryElements","nop","this","imposeConstantValueBoundaryConditions","Object","keys","forEach","boundaryKey","value","elementIndex","side","nodeIndex","globalNodeIndex","colIndex","BasisFunctions","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","maxX","maxY","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","undefined","fixedBoundaryElements","boundaryNodePairs","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","generate1DNodalNumbering","findBoundaryElements","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","assembleFrontPropagationMat","eikonalViscousTerm","mesh","nodesCoordinatesAndNumbering","totalElements","xCoordinates","yCoordinates","ksiDerivX","etaDerivX","ksiDerivY","etaDerivY","detJacobian","solutionDerivX","solutionDerivY","localToGlobalMap","basisFunctionDerivX","basisFunctionDerivY","basisFunctions","gaussPointsAndWeights","numNodes","localNodeIndex","gaussPointIndex1","basisFunctionsAndDerivatives","gaussPointIndex2","localNodeIndex1","localToGlobalMap1","localNodeIndex2","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","Error","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","map","fromWireValue","returnValue","parent","slice","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","r","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","arr","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","thermalBoundaryConditions","assembleSolidHeatTransferMat","newtonRaphsonResult","worker","feaWorker","isReady","_initWorker","Worker","URL","document","location","require","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","result","toFixed","getModelInfo","ping","terminate","async","file","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","parseInt","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","level","plotType","plotDivId","meshType","yData","xData","from","lineData","mode","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","l","t","b","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"feascript.umd.js","sources":["../src/methods/euclideanNormScript.js","../src/utilities/loggingScript.js","../src/methods/linearSystemSolverScript.js","../src/methods/jacobiSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/utilities/helperFunctionsScript.js","../src/solvers/genericBoundaryConditionsScript.js","../src/mesh/basisFunctionsScript.js","../src/mesh/meshGenerationScript.js","../src/methods/numericalIntegrationScript.js","../src/solvers/frontPropagationScript.js","../src/solvers/thermalBoundaryConditionsScript.js","../src/vendor/comlink.mjs","../src/FEAScript.js","../src/solvers/solidHeatTransferScript.js","../src/workers/workerScript.js","../src/index.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.js"],"sourcesContent":["// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to calculate the Euclidean norm of a vector\n * @param {array} vector - The input vector\n * @returns {number} The Euclidean norm of the vector\n */\nexport function euclideanNorm(vector) {\n let norm = 0;\n for (let i = 0; i < vector.length; i++) {\n norm += vector[i] * vector[i];\n }\n norm = Math.sqrt(norm);\n return norm;\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Global logging level\nlet currentLogLevel = \"basic\";\n\n/**\n * Function to set the logging system level\n * @param {string} level - Logging level (basic, debug)\n */\nexport function logSystem(level) {\n if (level !== \"basic\" && level !== \"debug\") {\n console.log(\n \"%c[WARN] Invalid log level: \" + level + \". Using basic instead.\",\n \"color: #FFC107; font-weight: bold;\"\n ); // Yellow for warnings\n currentLogLevel = \"basic\";\n } else {\n currentLogLevel = level;\n basicLog(`Log level set to: ${level}`);\n }\n}\n\n/**\n * Function to log debug messages - only logs if level is 'debug'\n * @param {string} message - Message to log\n */\nexport function debugLog(message) {\n if (currentLogLevel === \"debug\") {\n console.log(\"%c[DEBUG] \" + message, \"color: #2196F3; font-weight: bold;\"); // Blue color for debug\n }\n}\n\n/**\n * Function to log basic information - always logs\n * @param {string} message - Message to log\n */\nexport function basicLog(message) {\n console.log(\"%c[INFO] \" + message, \"color: #4CAF50; font-weight: bold;\"); // Green color for basic info\n}\n\n/**\n * Function to log error messages\n * @param {string} message - Message to log\n */\nexport function errorLog(message) {\n console.log(\"%c[ERROR] \" + message, \"color: #F44336; font-weight: bold;\"); // Red color for errors\n}\n\n/**\n * Function to handle version information and fetch the latest update date and release from GitHub\n */\nexport async function printVersion() {\n basicLog(\"Fetching latest FEAScript version information...\");\n try {\n const commitResponse = await fetch(\"https://api.github.com/repos/FEAScript/FEAScript/commits/main\");\n const commitData = await commitResponse.json();\n const latestCommitDate = new Date(commitData.commit.committer.date).toLocaleString();\n basicLog(`Latest FEAScript update: ${latestCommitDate}`);\n return latestCommitDate;\n } catch (error) {\n errorLog(\"Failed to fetch version information: \" + error);\n return \"Version information unavailable\";\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiSolver } from \"./jacobiSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to solve a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (\"lusolve\" or \"jacobi\")\n * @param {Array} jacobianMatrix - The coefficient matrix\n * @param {Array} residualVector - The right-hand side vector\n * @param {object} [options] - Additional options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum iterations for iterative methods\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance for iterative methods\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - converged: Boolean indicating whether the method converged (for iterative methods)\n * - iterations: Number of iterations performed (for iterative methods)\n */\nexport function solveLinearSystem(solverMethod, jacobianMatrix, residualVector, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n\n let solutionVector = [];\n let converged = true;\n let iterations = 0;\n\n // Solve the linear system based on the specified solver method\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n if (solverMethod === \"lusolve\") {\n // Use LU decomposition method\n solutionVector = math.lusolve(jacobianMatrix, residualVector);\n } else if (solverMethod === \"jacobi\") {\n // Use Jacobi method\n const initialGuess = new Array(residualVector.length).fill(0);\n const jacobiSolverResult = jacobiSolver(jacobianMatrix, residualVector, initialGuess, {\n maxIterations,\n tolerance,\n });\n\n // Log convergence information\n if (jacobiSolverResult.converged) {\n debugLog(`Jacobi method converged in ${jacobiSolverResult.iterations} iterations`);\n } else {\n debugLog(`Jacobi method did not converge after ${jacobiSolverResult.iterations} iterations`);\n }\n\n solutionVector = jacobiSolverResult.solutionVector;\n converged = jacobiSolverResult.converged;\n iterations = jacobiSolverResult.iterations;\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n return { solutionVector, converged, iterations };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method\n * @param {array} jacobianMatrix - The coefficient matrix (must be square)\n * @param {array} residualVector - The right-hand side vector\n * @param {array} initialGuess - Initial guess for solution vector\n * @param {object} [options] - Options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum number of iterations\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\nexport function jacobiSolver(jacobianMatrix, residualVector, initialGuess, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n const n = jacobianMatrix.length; // Size of the square matrix\n let x = [...initialGuess]; // Current solution (starts with initial guess)\n let xNew = new Array(n); // Next iteration's solution\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n // Perform one iteration\n for (let i = 0; i < n; i++) {\n let sum = 0;\n // Calculate sum of jacobianMatrix[i][j] * x[j] for j ≠ i\n for (let j = 0; j < n; j++) {\n if (j !== i) {\n sum += jacobianMatrix[i][j] * x[j];\n }\n }\n // Update xNew[i] using the Jacobi formula\n xNew[i] = (residualVector[i] - sum) / jacobianMatrix[i][i];\n }\n\n // Check convergence\n let maxDiff = 0;\n for (let i = 0; i < n; i++) {\n maxDiff = Math.max(maxDiff, Math.abs(xNew[i] - x[i]));\n }\n\n // Update x for next iteration\n x = [...xNew];\n\n // Successfully converged if maxDiff is less than tolerance\n if (maxDiff < tolerance) {\n return {\n solutionVector: x,\n iterations: iteration + 1,\n converged: true,\n };\n }\n }\n\n // maxIterations were reached without convergence\n return {\n solutionVector: x,\n iterations: maxIterations,\n converged: false,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { euclideanNorm } from \"../methods/euclideanNormScript.js\";\nimport { solveLinearSystem } from \"./linearSystemSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\nimport { calculateSystemSize } from \"../utilities/helperFunctionsScript.js\";\n\n/**\n * Function to solve a system of nonlinear equations using the Newton-Raphson method\n * @param {number} [maxIterations=100] - Maximum number of iterations\n * @param {number} [tolerance=1e-4] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\n\nexport function newtonRaphson(assembleMat, context, maxIterations = 100, tolerance = 1e-4) {\n let errorNorm = 0;\n let converged = false;\n let iterations = 0;\n let deltaX = [];\n let solutionVector = [];\n let jacobianMatrix = [];\n let residualVector = [];\n let nodesCoordinates = {};\n\n // Calculate system size directly from meshConfig\n let totalNodes = calculateSystemSize(context.meshConfig);\n\n // Initialize arrays with proper size\n for (let i = 0; i < totalNodes; i++) {\n deltaX[i] = 0;\n solutionVector[i] = 0;\n }\n\n // Initialize solution from context if available\n if (context.initialSolution && context.initialSolution.length === totalNodes) {\n solutionVector = [...context.initialSolution];\n }\n\n while (iterations < maxIterations && !converged) {\n // Update solution\n for (let i = 0; i < solutionVector.length; i++) {\n solutionVector[i] = Number(solutionVector[i]) + Number(deltaX[i]);\n }\n\n // Compute Jacobian and residual matrices\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleMat(\n context.meshConfig,\n context.boundaryConditions,\n solutionVector, // The solution vector is required in the case of a non-linear equation\n context.eikonalActivationFlag\n ));\n\n // Solve the linear system based on the specified solver method\n const linearSystemResult = solveLinearSystem(context.solverMethod, jacobianMatrix, residualVector);\n deltaX = linearSystemResult.solutionVector;\n\n // Check convergence\n errorNorm = euclideanNorm(deltaX);\n\n // Norm for each iteration\n basicLog(`Newton-Raphson iteration ${iterations + 1}: Error norm = ${errorNorm.toExponential(4)}`);\n\n if (errorNorm <= tolerance) {\n converged = true;\n } else if (errorNorm > 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n nodesCoordinates,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Helper function to calculate system size from mesh configuration\n * @param {object} meshConfig - Mesh configuration object\n * @returns {number} Total number of nodes in the system\n */\nexport function calculateSystemSize(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, elementOrder, parsedMesh } = meshConfig;\n\n if (parsedMesh && parsedMesh.nodesXCoordinates) {\n // For parsed meshes (like from GMSH)\n return parsedMesh.nodesXCoordinates.length;\n } else {\n // For geometry-based meshes\n let nodesX,\n nodesY = 1;\n\n if (elementOrder === \"linear\") {\n nodesX = numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = numElementsY + 1;\n } else if (elementOrder === \"quadratic\") {\n nodesX = 2 * numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = 2 * numElementsY + 1;\n }\n\n return nodesX * nodesY;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n debugLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n if (\n this.numElementsX === null ||\n this.maxX === null ||\n this.numElementsY === null ||\n this.maxY === null\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n \n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\n\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the front propagation matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation (ranges from 0 to 1)\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleFrontPropagationMat(\n meshConfig,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n // TODO: The mesh generation step should be moved outside of the assembleFrontPropagationMat function so that not performed in every Newton-Raphson iteration\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n let solutionDerivX; // The x-derivative of the solution\n let solutionDerivY; // The y-derivative of the solution\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n detJacobian = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n detJacobian = ksiDerivX;\n }\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n // 2D front propagation (eikonal) equation\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n solutionDerivX = 0;\n solutionDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x & y-derivatives of basis functions and x & y-derivatives of the solution\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n // The x-derivative of the solution\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n // The y-derivative of the solution\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector - Viscous term: Add diffusion contribution to stabilize the solution\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n // residualVector - Eikonal term: Add the eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix - Viscous term: Add the Jacobian contribution from the diffusion term\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n // jacobianMatrix - Eikonal term: Add the Jacobian contribution from the eikonal equation\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n (detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)\n ) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n }\n\n // Create an instance of GenericBoundaryConditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions (Robin type)\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n let nodesCoordinates = {};\n let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term - Used in frontPropagationScript\n let newtonRaphsonIterations;\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleSolidHeatTransferMat(\n this.meshConfig,\n this.boundaryConditions\n ));\n\n // Solve the assembled linear system\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n\n // Create context object with all necessary properties\n const context = {\n meshConfig: this.meshConfig,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n nodesCoordinates = newtonRaphsonResult.nodesCoordinates;\n solutionVector = newtonRaphsonResult.solutionVector;\n newtonRaphsonIterations = newtonRaphsonResult.iterations;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the solid heat transfer matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n // 2D solid heat transfer\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Create an instance of ThermalBoundaryConditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.3\";","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","debugLog","message","console","log","basicLog","errorLog","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","math","lusolve","jacobiSolverResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiSolver","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","nodesCoordinates","totalNodes","meshConfig","meshDimension","numElementsX","numElementsY","elementOrder","parsedMesh","nodesXCoordinates","nodesX","nodesY","calculateSystemSize","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","GenericBoundaryConditions","constructor","boundaryElements","nop","this","imposeConstantValueBoundaryConditions","Object","keys","forEach","boundaryKey","value","elementIndex","side","nodeIndex","globalNodeIndex","colIndex","BasisFunctions","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","maxX","maxY","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","undefined","fixedBoundaryElements","boundaryNodePairs","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","generate1DNodalNumbering","findBoundaryElements","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","assembleFrontPropagationMat","eikonalViscousTerm","mesh","nodesCoordinatesAndNumbering","totalElements","xCoordinates","yCoordinates","ksiDerivX","etaDerivX","ksiDerivY","etaDerivY","detJacobian","solutionDerivX","solutionDerivY","localToGlobalMap","basisFunctionDerivX","basisFunctionDerivY","basisFunctions","gaussPointsAndWeights","numNodes","localNodeIndex","gaussPointIndex1","basisFunctionsAndDerivatives","gaussPointIndex2","localNodeIndex1","localToGlobalMap1","localNodeIndex2","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","Error","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","map","fromWireValue","returnValue","parent","slice","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","r","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","arr","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","thermalBoundaryConditions","assembleSolidHeatTransferMat","newtonRaphsonResult","worker","feaWorker","isReady","_initWorker","Worker","URL","document","location","require","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","result","toFixed","getModelInfo","ping","terminate","async","file","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","parseInt","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","level","plotType","plotDivId","meshType","yData","xData","from","lineData","mode","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","l","t","b","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString"],"mappings":"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"} \ No newline at end of file diff --git a/package.json b/package.json index 2539c15..8e54bf2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "feascript", - "version": "0.1.2", - "description": "A lightweight finite element simulation library built in JavaScript for browser-based physics and engineering simulations", + "version": "0.1.3", + "description": "Lightweight finite element simulation library built in JavaScript for browser-based physics and engineering simulations", "main": "dist/feascript.cjs.js", "module": "dist/feascript.esm.js", "browser": "dist/feascript.umd.js", @@ -40,6 +40,10 @@ { "name": "sridhar-mani", "url": "https://www.npmjs.com/~sridhar-mani" + }, + { + "name": "Felipe Ferrari", + "url": "https://github.com/ferrari212" } ], "license": "MIT", @@ -47,7 +51,7 @@ "bugs": { "url": "https://github.com/FEAScript/FEAScript-core/issues" }, - "homepage": "https://github.com/FEAScript/FEAScript-core#readme", + "homepage": "https://feascript.com/", "publishConfig": { "access": "public" }, diff --git a/src/index.js b/src/index.js index 12a5482..b3309b0 100644 --- a/src/index.js +++ b/src/index.js @@ -13,4 +13,4 @@ export { importGmshQuadTri } from "./readers/gmshReaderScript.js"; export { logSystem, printVersion } from "./utilities/loggingScript.js"; export { plotSolution } from "./visualization/plotSolutionScript.js"; export { FEAScriptWorker } from "./workers/workerScript.js"; -export const VERSION = "0.1.2"; \ No newline at end of file +export const VERSION = "0.1.3"; \ No newline at end of file From c75e162b2b1d502ad1ab6a84d2d37fab9bb84b4d Mon Sep 17 00:00:00 2001 From: Nikos Chamakos Date: Fri, 22 Aug 2025 15:21:11 +0300 Subject: [PATCH 04/24] Feature/frontal solver (#33) * Refactor solver imports * chore: bump version to 0.1.3 and update description in package.json - Updated version from 0.1.2 to 0.1.3 - Modified description for clarity - Added contributor Felipe Ferrari to package.json - Changed homepage URL to https://feascript.com/ - Updated version constant in src/index.js to 0.1.3 --- CONTRIBUTING.md | 19 +++- NOTICE.md | 12 +-- README.md | 102 ++++++++++-------- dist/feascript.cjs.js | 2 +- dist/feascript.cjs.js.map | 2 +- dist/feascript.esm.js | 2 +- dist/feascript.esm.js.map | 2 +- dist/feascript.umd.js | 2 +- dist/feascript.umd.js.map | 2 +- package.json | 10 +- src/FEAScript.js | 3 +- src/index.js | 2 +- ...iMethodScript.js => jacobiSolverScript.js} | 2 +- ...mScript.js => linearSystemSolverScript.js} | 16 +-- src/methods/newtonRaphsonScript.js | 2 +- 15 files changed, 105 insertions(+), 75 deletions(-) rename src/methods/{jacobiMethodScript.js => jacobiSolverScript.js} (97%) rename src/methods/{linearSystemScript.js => linearSystemSolverScript.js} (82%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 47d724f..ee870bd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,11 +40,11 @@ To contribute a new feature or fix: All files in the FEAScript-core codebase should follow this structure: -1. **Banner**: All files start with the FEAScript ASCII art banner +1. **Banner**: All files start with the FEAScript ASCII art banner. 2. **Imports**: - - External imports (from npm packages) first, alphabetically ordered - - Internal imports next, grouped by module/folder -3. **Classes/Functions**: Implementation with proper JSDoc comments + - External imports (from npm packages) first, alphabetically ordered. + - Internal imports next, grouped by module/folder. +3. **Classes/Functions**: Implementation with proper JSDoc comments. Example: @@ -88,3 +88,14 @@ export class MyClass { } } ``` + +## File Naming Convention + +All JavaScript source files in FEAScript end with the suffix `Script` before the `.js` extension (e.g., `loggingScript.js`, `meshGenerationScript.js`, `newtonRaphsonScript.js`). This is an explicit, project‑level stylistic choice to: + +- Visually distinguish internal FEAScript modules from third‑party or external library files. +- Keep historical and stylistic consistency across the codebase. + +Exceptions: +- Public entry file: `index.js` (standard entry point convention). +- Core model file: `FEAScript.js` (matches the library name; appending "Script" would be redundant). diff --git a/NOTICE.md b/NOTICE.md index 511922e..b5d901d 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -1,16 +1,14 @@ FEAScript makes use of the following third-party software: 1. **math.js** - - License: Apache 2.0 License + - License: Apache 2.0 (https://github.com/josdejong/mathjs/blob/develop/LICENSE) - Source: https://github.com/josdejong/mathjs - - License: https://github.com/josdejong/mathjs/blob/develop/LICENSE + 2. **plotly.js** - - License: MIT License + - License: MIT (https://github.com/plotly/plotly.js/blob/master/LICENSE) - Source: https://github.com/plotly/plotly.js/tree/master - - License: https://github.com/plotly/plotly.js/blob/master/LICENSE 3. **Comlink** - - License: Apache 2.0 License - - Source: https://github.com/GoogleChromeLabs/comlink - - License: https://github.com/GoogleChromeLabs/comlink/blob/main/LICENSE \ No newline at end of file + - License: Apache 2.0 (https://github.com/GoogleChromeLabs/comlink/blob/main/LICENSE) + - Source: https://github.com/GoogleChromeLabs/comlink \ No newline at end of file diff --git a/README.md b/README.md index fe152ab..eaa9056 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,33 @@ FEAScript Logo # FEAScript-core -[![npm version](https://img.shields.io/npm/v/feascript)](https://www.npmjs.com/package/feascript) + +[![npm version](https://img.shields.io/npm/v/feascript)](https://www.npmjs.com/package/feascript) [FEAScript](https://feascript.com/) is a lightweight finite element simulation library built in JavaScript. It empowers users to create and execute simulations for physics and engineering applications in both browser-based and server-side environments. This is the core library of FEAScript. > 🚧 **FEAScript is currently under heavy development.** Functionality and interfaces may change rapidly as new features and enhancements are introduced. 🚧 +## Contents + +- [Installation](#installation) +- [Example Usage](#example-usage) +- [FEAScript Platform](#feascript-platform) +- [Contribute](#contribute) +- [License](#license) + ## Installation FEAScript is entirely implemented in pure JavaScript and can run in two environments: -1. **In the browser** with a simple HTML page, where all simulations are executed locally without any installations or using any cloud services -2. **Via Node.js** with plain JavaScript files, for server-side simulations +1. **In the browser** with a simple HTML page, where all simulations are executed locally without any installations or using any cloud services. +2. **Via Node.js** with plain JavaScript files, for server-side simulations. ### Option 1: In the Browser You can use FEAScript in browser environments in two ways: -**Direct Import from CDN**: -Add this to your HTML file: +**Direct Import from the Web (ES Module):** ```html ``` -**Download and Use Locally**: -1. Download the latest release from [GitHub Releases](https://github.com/FEAScript/FEAScript-core/releases) -2. Include it in your HTML file: +**Download and Use Locally:** ```html ``` -For browser-based examples and use cases, visit [our website tutorials](https://feascript.com/#tutorials). +You can Download the latest release from [GitHub Releases](https://github.com/FEAScript/FEAScript-core/releases). Explore various browser-based examples and use cases in our [website](https://feascript.com/#tutorials). ### Option 2: Via Node.js +Install FEAScript and its peer dependencies from npm: + ```bash -# Install FEAScript and its peer dependencies from npm npm install feascript mathjs plotly.js ``` -Then import it in your JavaScript/TypeScript file: +Then, import it in your JavaScript file: ```javascript import { FEAScriptModel } from "feascript"; ``` -**Important:** FEAScript is built as an ES module. If you're starting a completely new project (outside this repository), make sure to configure it to use ES modules by (when running examples from within this repository, this step is not needed as the root package.json already has the proper configuration): +**Important:** FEAScript is built as an ES module. If you're starting a completely new project (outside this repository), make sure to configure it to use ES modules by: ```bash # Create package.json with type=module for ES modules support echo '{"type":"module"}' > package.json ``` -Explore various Node.js examples and use cases [here](https://github.com/FEAScript/FEAScript-core/tree/main/examples). +When running examples from within this repository, this step is not needed as the root package.json already has the proper configuration. Explore various Node.js examples and use cases [here](https://github.com/FEAScript/FEAScript-core/tree/main/examples). ## Example Usage -**Browser Import:** -```javascript -// Import FEAScript library in browser -import { FEAScriptModel } from "https://core.feascript.com/dist/feascript.esm.js"; -``` +This is an indicative example of FEAScript, shown for execution in the browser. Adapt paths, solver types, and boundary conditions as needed for your specific problem: -**Node.js Import:** -```javascript -// Import FEAScript library in Node.js -import { FEAScriptModel } from "feascript"; -``` -```javascript -// Create and configure model -const model = new FEAScriptModel(); -model.setSolverConfig("solverType"); // e.g., "solidHeatTransfer" for a stationary solid heat transfer case -model.setMeshConfig({ - meshDimension: "1D" | "2D", // Mesh dimension - elementOrder: "linear" | "quadratic", // Element order - numElementsX: number, // Number of elements in x-direction - numElementsY: number, // Number of elements in y-direction (for 2D) - maxX: number, // Domain length in x-direction - maxY: number, // Domain length in y-direction (for 2D) -}); - -// Apply boundary conditions -model.addBoundaryCondition("boundaryIndex", ["conditionType", /* parameters */]); - -// Solve -model.setSolverMethod("linearSolver"); // lusolve (via mathjs) or jacobi -const { solutionVector, nodesCoordinates } = model.solve(); +```html + + + + + ``` +## FEAScript Platform + +For users who prefer a visual approach to creating simulations, we offer the [FEAScript platform](https://platform.feascript.com/) - a browser-based visual editor built on the [Blockly](https://developers.google.com/blockly) library. This no-code interface allows you to: + +- Build and run finite element simulations directly in your browser by connecting visual blocks +- Create complex simulations without writing any JavaScript code +- Save and load projects in XML format for easy sharing and reuse + +While FEAScript's JavaScript API offers full programmatic control for advanced customization, the FEAScript platform provides an accessible entry point for users without coding experience. + ## Contribute We warmly welcome contributors to help expand and refine FEAScript. Please see the [CONTRIBUTING.md](./CONTRIBUTING.md) file for detailed guidance on how to contribute. diff --git a/dist/feascript.cjs.js b/dist/feascript.cjs.js index 0291ca2..bc914b9 100644 --- a/dist/feascript.cjs.js +++ b/dist/feascript.cjs.js @@ -4,5 +4,5 @@ * Copyright 2019 Google LLC * SPDX-License-Identifier: Apache-2.0 */ -const p=Symbol("Comlink.proxy"),g=Symbol("Comlink.endpoint"),y=Symbol("Comlink.releaseProxy"),b=Symbol("Comlink.finalizer"),E=Symbol("Comlink.thrown"),$=e=>"object"==typeof e&&null!==e||"function"==typeof e,M=new Map([["proxy",{canHandle:e=>$(e)&&e[p],serialize(e){const{port1:t,port2:n}=new MessageChannel;return v(e,t),[n,[n]]},deserialize:e=>(e.start(),w(e))}],["throw",{canHandle:e=>$(e)&&E in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function v(e,t=globalThis,n=["*"]){t.addEventListener("message",(function s(o){if(!o||!o.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,o.origin))return void console.warn(`Invalid origin '${o.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},o.data),l=(o.data.argumentList||[]).map(k);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=k(o.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[p]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;v(e,n),d=function(e,t){return F.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[E]:0}}Promise.resolve(d).catch((e=>({value:e,[E]:0}))).then((n=>{const[o,a]=X(n);t.postMessage(Object.assign(Object.assign({},o),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",s),C(t),b in e&&"function"==typeof e[b]&&e[b]())})).catch((e=>{const[n,s]=X({value:new TypeError("Unserializable return value"),[E]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),s)}))})),t.start&&t.start()}function C(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function w(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const s=n.get(t.id);if(s)try{s(t)}finally{n.delete(t.id)}})),D(e,n,[],t)}function x(e){if(e)throw new Error("Proxy has been released and is not useable")}function S(e){return T(e,new Map,{type:"RELEASE"}).then((()=>{C(e)}))}const N=new WeakMap,O="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(N.get(e)||0)-1;N.set(e,t),0===t&&S(e)}));function D(e,t,n=[],s=function(){}){let o=!1;const i=new Proxy(s,{get(s,r){if(x(o),r===y)return()=>{!function(e){O&&O.unregister(e)}(i),S(e),t.clear(),o=!0};if("then"===r){if(0===n.length)return{then:()=>i};const s=T(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(k);return s.then.bind(s)}return D(e,t,[...n,r])},set(s,i,r){x(o);const[a,l]=X(r);return T(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(k)},apply(s,i,r){x(o);const a=n[n.length-1];if(a===g)return T(e,t,{type:"ENDPOINT"}).then(k);if("bind"===a)return D(e,t,n.slice(0,-1));const[l,d]=A(r);return T(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(k)},construct(s,i){x(o);const[r,a]=A(i);return T(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(k)}});return function(e,t){const n=(N.get(t)||0)+1;N.set(t,n),O&&O.register(e,t,e)}(i,e),i}function A(e){const t=e.map(X);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const F=new WeakMap;function X(e){for(const[t,n]of M)if(n.canHandle(e)){const[s,o]=n.serialize(e);return[{type:"HANDLER",name:t,value:s},o]}return[{type:"RAW",value:e},F.get(e)||[]]}function k(e){switch(e.type){case"HANDLER":return M.get(e.name).deserialize(e.value);case"RAW":return e.value}}function T(e,t,n,s){return new Promise((o=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,o),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),s)}))}exports.FEAScriptModel=class{constructor(){this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",s("FEAScriptModel instance created")}setSolverConfig(e){this.solverConfig=e,n(`Solver config set to: ${e}`)}setMeshConfig(e){this.meshConfig=e,n(`Mesh config set with dimensions: ${e.meshDimension}`)}addBoundaryCondition(e,t){this.boundaryConditions[e]=t,n(`Boundary condition added for boundary: ${e}, type: ${t[0]}`)}setSolverMethod(e){this.solverMethod=e,n(`Solver method set to: ${e}`)}solve(){if(!this.solverConfig||!this.meshConfig||!this.boundaryConditions){const e="Solver config, mesh config, and boundary conditions must be set before solving.";throw console.error(e),new Error(e)}let e=[],t=[],a=[],d=[],p={};if(s("Beginning solving process..."),console.time("totalSolvingTime"),"solidHeatTransferScript"===this.solverConfig){s(`Using solver: ${this.solverConfig}`),({jacobianMatrix:e,residualVector:t,nodesCoordinates:p}=function(e,t){s("Starting solid heat transfer matrix assembly...");const{meshDimension:i,numElementsX:r,numElementsY:a,maxX:d,maxY:c,elementOrder:p,parsedMesh:g}=e;let y;n("Generating mesh..."),"1D"===i?y=new m({numElementsX:r,maxX:d,elementOrder:p,parsedMesh:g}):"2D"===i?y=new h({numElementsX:r,maxX:d,numElementsY:a,maxY:c,elementOrder:p,parsedMesh:g}):o("Mesh dimension must be either '1D' or '2D'.");const b=y.boundaryElementsProcessed?y.parsedMesh:y.generateMesh();let E,$,M=b.nodesXCoordinates,v=b.nodesYCoordinates,C=b.totalNodesX,w=b.totalNodesY,x=b.nodalNumbering,S=b.boundaryElements;null!=g?(E=x.length,$=M.length,n(`Using parsed mesh with ${E} elements and ${$} nodes`)):(E=r*("2D"===i?a:1),$=C*("2D"===i?w:1),n(`Using mesh generated from geometry with ${E} elements and ${$} nodes`));let N,O,D,A,F,X,k,T=[],P=[],Y=[],R=[],W=[],I=[],B=[],j=[],q=[],V=[];for(let e=0;e<$;e++){q[e]=0,V.push([]);for(let t=0;t<$;t++)V[e][t]=0}const L=new l({meshDimension:i,elementOrder:p});let G=new u({meshDimension:i,elementOrder:p}).getGaussPointsAndWeights();P=G.gaussPoints,Y=G.gaussWeights;const U=x[0].length;for(let e=0;e0&&(o.initialSolution=[...a]);const s=r(c,o,100,1e-4);e=s.jacobianMatrix,t=s.residualVector,p=s.nodesCoordinates,a=s.solutionVector,n+=.2}}return console.timeEnd("totalSolvingTime"),s("Solving process completed"),{solutionVector:a,nodesCoordinates:p}}},exports.FEAScriptWorker=class{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js","undefined"==typeof document?new(require("url").URL)("file:"+__filename).href:document.currentScript&&"SCRIPT"===document.currentScript.tagName.toUpperCase()&&document.currentScript.src||new URL("feascript.cjs.js",document.baseURI).href),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=w(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const s=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(s,1e3)};s()}))}async setSolverConfig(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),s("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),s(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),s("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return s(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}},exports.VERSION="0.1.2",exports.importGmshQuadTri=async e=>{let t={nodesXCoordinates:[],nodesYCoordinates:[],nodalNumbering:{quadElements:[],triangleElements:[]},boundaryElements:[],boundaryConditions:[],boundaryNodePairs:{},gmshV:0,ascii:!1,fltBytes:"8",totalNodesX:0,totalNodesY:0,physicalPropMap:[],elementTypes:{}},s=(await e.text()).split("\n").map((e=>e.trim())).filter((e=>""!==e&&" "!==e)),o="",i=0,r=0,a=0,l=0,d={numNodes:0},m=0,h=[],u=0,c=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},g=0,y={};for(;i""!==e));if("meshFormat"===o)t.gmshV=parseFloat(n[0]),t.ascii="0"===n[1],t.fltBytes=n[2];else if("physicalNames"===o){if(n.length>=3){if(!/^\d+$/.test(n[0])){i++;continue}const e=parseInt(n[0],10),s=parseInt(n[1],10);let o=n.slice(2).join(" ");o=o.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:s,dimension:e,name:o})}}else if("nodes"===o){if(0===r){r=parseInt(n[0],10),a=parseInt(n[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;y[n]||(y[n]=[]),y[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);g++,g===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=y[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),n(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t},exports.logSystem=function(e){"basic"!==e&&"debug"!==e?(console.log("%c[WARN] Invalid log level: "+e+". Using basic instead.","color: #FFC107; font-weight: bold;"),t="basic"):(t=e,s(`Log level set to: ${e}`))},exports.plotSolution=function(e,t,n,s,o,i,r="structured"){const{nodesXCoordinates:a,nodesYCoordinates:l}=t;if("1D"===s&&"line"===o){let t;t=e.length>0&&Array.isArray(e[0])?e.map((e=>e[0])):e;let s=Array.from(a),o={x:s,y:t,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},r=Math.min(window.innerWidth,700),l=Math.max(...s),d=r/l,m={title:`line plot - ${n}`,width:Math.max(d*l,400),height:350,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:70,r:40,t:50,b:50}};Plotly.newPlot(i,[o],m,{responsive:!0})}else if("2D"===s&&"contour"===o){const t="structured"===r,s=new Set(a).size,d=new Set(l).size;let m;m=Array.isArray(e[0])?e.map((e=>e[0])):e;let h=Math.min(window.innerWidth,700),u=Math.max(...a),c=Math.max(...l)/u,f=Math.min(h,600),p={title:`${o} plot - ${n}`,width:f,height:f*c*.8,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"};if(t){const t=s,n=d;math.reshape(Array.from(a),[t,n]);let o=math.reshape(Array.from(l),[t,n]),r=math.reshape(Array.from(e),[t,n]),m=math.transpose(r),h=[];for(let e=0;e"object"==typeof e&&null!==e||"function"==typeof e,M=new Map([["proxy",{canHandle:e=>$(e)&&e[p],serialize(e){const{port1:t,port2:n}=new MessageChannel;return v(e,t),[n,[n]]},deserialize:e=>(e.start(),w(e))}],["throw",{canHandle:e=>$(e)&&E in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function v(e,t=globalThis,n=["*"]){t.addEventListener("message",(function s(o){if(!o||!o.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,o.origin))return void console.warn(`Invalid origin '${o.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},o.data),l=(o.data.argumentList||[]).map(k);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=k(o.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[p]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;v(e,n),d=function(e,t){return F.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[E]:0}}Promise.resolve(d).catch((e=>({value:e,[E]:0}))).then((n=>{const[o,a]=X(n);t.postMessage(Object.assign(Object.assign({},o),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",s),C(t),b in e&&"function"==typeof e[b]&&e[b]())})).catch((e=>{const[n,s]=X({value:new TypeError("Unserializable return value"),[E]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),s)}))})),t.start&&t.start()}function C(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function w(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const s=n.get(t.id);if(s)try{s(t)}finally{n.delete(t.id)}})),D(e,n,[],t)}function x(e){if(e)throw new Error("Proxy has been released and is not useable")}function S(e){return T(e,new Map,{type:"RELEASE"}).then((()=>{C(e)}))}const N=new WeakMap,O="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(N.get(e)||0)-1;N.set(e,t),0===t&&S(e)}));function D(e,t,n=[],s=function(){}){let o=!1;const i=new Proxy(s,{get(s,r){if(x(o),r===y)return()=>{!function(e){O&&O.unregister(e)}(i),S(e),t.clear(),o=!0};if("then"===r){if(0===n.length)return{then:()=>i};const s=T(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(k);return s.then.bind(s)}return D(e,t,[...n,r])},set(s,i,r){x(o);const[a,l]=X(r);return T(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(k)},apply(s,i,r){x(o);const a=n[n.length-1];if(a===g)return T(e,t,{type:"ENDPOINT"}).then(k);if("bind"===a)return D(e,t,n.slice(0,-1));const[l,d]=A(r);return T(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(k)},construct(s,i){x(o);const[r,a]=A(i);return T(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(k)}});return function(e,t){const n=(N.get(t)||0)+1;N.set(t,n),O&&O.register(e,t,e)}(i,e),i}function A(e){const t=e.map(X);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const F=new WeakMap;function X(e){for(const[t,n]of M)if(n.canHandle(e)){const[s,o]=n.serialize(e);return[{type:"HANDLER",name:t,value:s},o]}return[{type:"RAW",value:e},F.get(e)||[]]}function k(e){switch(e.type){case"HANDLER":return M.get(e.name).deserialize(e.value);case"RAW":return e.value}}function T(e,t,n,s){return new Promise((o=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,o),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),s)}))}exports.FEAScriptModel=class{constructor(){this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",s("FEAScriptModel instance created")}setSolverConfig(e){this.solverConfig=e,n(`Solver config set to: ${e}`)}setMeshConfig(e){this.meshConfig=e,n(`Mesh config set with dimensions: ${e.meshDimension}`)}addBoundaryCondition(e,t){this.boundaryConditions[e]=t,n(`Boundary condition added for boundary: ${e}, type: ${t[0]}`)}setSolverMethod(e){this.solverMethod=e,n(`Solver method set to: ${e}`)}solve(){if(!this.solverConfig||!this.meshConfig||!this.boundaryConditions){const e="Solver config, mesh config, and boundary conditions must be set before solving.";throw console.error(e),new Error(e)}let e=[],t=[],a=[],d=[],p={};if(s("Beginning solving process..."),console.time("totalSolvingTime"),"solidHeatTransferScript"===this.solverConfig){s(`Using solver: ${this.solverConfig}`),({jacobianMatrix:e,residualVector:t,nodesCoordinates:p}=function(e,t){s("Starting solid heat transfer matrix assembly...");const{meshDimension:i,numElementsX:r,numElementsY:a,maxX:d,maxY:c,elementOrder:p,parsedMesh:g}=e;let y;n("Generating mesh..."),"1D"===i?y=new m({numElementsX:r,maxX:d,elementOrder:p,parsedMesh:g}):"2D"===i?y=new h({numElementsX:r,maxX:d,numElementsY:a,maxY:c,elementOrder:p,parsedMesh:g}):o("Mesh dimension must be either '1D' or '2D'.");const b=y.boundaryElementsProcessed?y.parsedMesh:y.generateMesh();let E,$,M=b.nodesXCoordinates,v=b.nodesYCoordinates,C=b.totalNodesX,w=b.totalNodesY,x=b.nodalNumbering,S=b.boundaryElements;null!=g?(E=x.length,$=M.length,n(`Using parsed mesh with ${E} elements and ${$} nodes`)):(E=r*("2D"===i?a:1),$=C*("2D"===i?w:1),n(`Using mesh generated from geometry with ${E} elements and ${$} nodes`));let N,O,D,A,F,X,k,T=[],P=[],Y=[],R=[],W=[],I=[],B=[],j=[],q=[],V=[];for(let e=0;e<$;e++){q[e]=0,V.push([]);for(let t=0;t<$;t++)V[e][t]=0}const L=new l({meshDimension:i,elementOrder:p});let G=new u({meshDimension:i,elementOrder:p}).getGaussPointsAndWeights();P=G.gaussPoints,Y=G.gaussWeights;const U=x[0].length;for(let e=0;e0&&(o.initialSolution=[...a]);const s=r(c,o,100,1e-4);e=s.jacobianMatrix,t=s.residualVector,p=s.nodesCoordinates,a=s.solutionVector,n+=.2}}return console.timeEnd("totalSolvingTime"),s("Solving process completed"),{solutionVector:a,nodesCoordinates:p}}},exports.FEAScriptWorker=class{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js","undefined"==typeof document?new(require("url").URL)("file:"+__filename).href:document.currentScript&&"SCRIPT"===document.currentScript.tagName.toUpperCase()&&document.currentScript.src||new URL("feascript.cjs.js",document.baseURI).href),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=w(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const s=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(s,1e3)};s()}))}async setSolverConfig(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),s("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),s(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),s("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return s(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}},exports.VERSION="0.1.3",exports.importGmshQuadTri=async e=>{let t={nodesXCoordinates:[],nodesYCoordinates:[],nodalNumbering:{quadElements:[],triangleElements:[]},boundaryElements:[],boundaryConditions:[],boundaryNodePairs:{},gmshV:0,ascii:!1,fltBytes:"8",totalNodesX:0,totalNodesY:0,physicalPropMap:[],elementTypes:{}},s=(await e.text()).split("\n").map((e=>e.trim())).filter((e=>""!==e&&" "!==e)),o="",i=0,r=0,a=0,l=0,d={numNodes:0},m=0,h=[],u=0,c=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},g=0,y={};for(;i""!==e));if("meshFormat"===o)t.gmshV=parseFloat(n[0]),t.ascii="0"===n[1],t.fltBytes=n[2];else if("physicalNames"===o){if(n.length>=3){if(!/^\d+$/.test(n[0])){i++;continue}const e=parseInt(n[0],10),s=parseInt(n[1],10);let o=n.slice(2).join(" ");o=o.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:s,dimension:e,name:o})}}else if("nodes"===o){if(0===r){r=parseInt(n[0],10),a=parseInt(n[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;y[n]||(y[n]=[]),y[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);g++,g===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=y[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),n(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t},exports.logSystem=function(e){"basic"!==e&&"debug"!==e?(console.log("%c[WARN] Invalid log level: "+e+". Using basic instead.","color: #FFC107; font-weight: bold;"),t="basic"):(t=e,s(`Log level set to: ${e}`))},exports.plotSolution=function(e,t,n,s,o,i,r="structured"){const{nodesXCoordinates:a,nodesYCoordinates:l}=t;if("1D"===s&&"line"===o){let t;t=e.length>0&&Array.isArray(e[0])?e.map((e=>e[0])):e;let s=Array.from(a),o={x:s,y:t,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},r=Math.min(window.innerWidth,700),l=Math.max(...s),d=r/l,m={title:`line plot - ${n}`,width:Math.max(d*l,400),height:350,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:70,r:40,t:50,b:50}};Plotly.newPlot(i,[o],m,{responsive:!0})}else if("2D"===s&&"contour"===o){const t="structured"===r,s=new Set(a).size,d=new Set(l).size;let m;m=Array.isArray(e[0])?e.map((e=>e[0])):e;let h=Math.min(window.innerWidth,700),u=Math.max(...a),c=Math.max(...l)/u,f=Math.min(h,600),p={title:`${o} plot - ${n}`,width:f,height:f*c*.8,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"};if(t){const t=s,n=d;math.reshape(Array.from(a),[t,n]);let o=math.reshape(Array.from(l),[t,n]),r=math.reshape(Array.from(e),[t,n]),m=math.transpose(r),h=[];for(let e=0;e 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n nodesCoordinates,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Helper function to calculate system size from mesh configuration\n * @param {object} meshConfig - Mesh configuration object\n * @returns {number} Total number of nodes in the system\n */\nexport function calculateSystemSize(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, elementOrder, parsedMesh } = meshConfig;\n\n if (parsedMesh && parsedMesh.nodesXCoordinates) {\n // For parsed meshes (like from GMSH)\n return parsedMesh.nodesXCoordinates.length;\n } else {\n // For geometry-based meshes\n let nodesX,\n nodesY = 1;\n\n if (elementOrder === \"linear\") {\n nodesX = numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = numElementsY + 1;\n } else if (elementOrder === \"quadratic\") {\n nodesX = 2 * numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = 2 * numElementsY + 1;\n }\n\n return nodesX * nodesY;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n debugLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n if (\n this.numElementsX === null ||\n this.maxX === null ||\n this.numElementsY === null ||\n this.maxY === null\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n \n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\n\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the front propagation matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation (ranges from 0 to 1)\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleFrontPropagationMat(\n meshConfig,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n // TODO: The mesh generation step should be moved outside of the assembleFrontPropagationMat function so that not performed in every Newton-Raphson iteration\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n let solutionDerivX; // The x-derivative of the solution\n let solutionDerivY; // The y-derivative of the solution\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n detJacobian = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n detJacobian = ksiDerivX;\n }\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n // 2D front propagation (eikonal) equation\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n solutionDerivX = 0;\n solutionDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x & y-derivatives of basis functions and x & y-derivatives of the solution\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n // The x-derivative of the solution\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n // The y-derivative of the solution\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector - Viscous term: Add diffusion contribution to stabilize the solution\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n // residualVector - Eikonal term: Add the eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix - Viscous term: Add the Jacobian contribution from the diffusion term\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n // jacobianMatrix - Eikonal term: Add the Jacobian contribution from the eikonal equation\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n (detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)\n ) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n }\n\n // Create an instance of GenericBoundaryConditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions (Robin type)\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiMethod } from \"./methods/jacobiMethodScript.js\";\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n let nodesCoordinates = {};\n let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term - Used in frontPropagationScript\n let newtonRaphsonIterations;\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleSolidHeatTransferMat(\n this.meshConfig,\n this.boundaryConditions\n ));\n\n // Solve the assembled linear system\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n\n // Create context object with all necessary properties\n const context = {\n meshConfig: this.meshConfig,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n nodesCoordinates = newtonRaphsonResult.nodesCoordinates;\n solutionVector = newtonRaphsonResult.solutionVector;\n newtonRaphsonIterations = newtonRaphsonResult.iterations;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the solid heat transfer matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n // 2D solid heat transfer\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Create an instance of ThermalBoundaryConditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.2\";","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","debugLog","message","console","log","basicLog","errorLog","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","math","lusolve","jacobiResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiMethod","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","nodesCoordinates","totalNodes","meshConfig","meshDimension","numElementsX","numElementsY","elementOrder","parsedMesh","nodesXCoordinates","nodesX","nodesY","calculateSystemSize","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","GenericBoundaryConditions","constructor","boundaryElements","nop","this","imposeConstantValueBoundaryConditions","Object","keys","forEach","boundaryKey","value","elementIndex","side","nodeIndex","globalNodeIndex","colIndex","BasisFunctions","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","maxX","maxY","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","undefined","fixedBoundaryElements","boundaryNodePairs","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","generate1DNodalNumbering","findBoundaryElements","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","assembleFrontPropagationMat","eikonalViscousTerm","mesh","nodesCoordinatesAndNumbering","totalElements","xCoordinates","yCoordinates","ksiDerivX","etaDerivX","ksiDerivY","etaDerivY","detJacobian","solutionDerivX","solutionDerivY","localToGlobalMap","basisFunctionDerivX","basisFunctionDerivY","basisFunctions","gaussPointsAndWeights","numNodes","localNodeIndex","gaussPointIndex1","basisFunctionsAndDerivatives","gaussPointIndex2","localNodeIndex1","localToGlobalMap1","localNodeIndex2","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","Error","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","map","fromWireValue","returnValue","parent","slice","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","r","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","arr","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","thermalBoundaryConditions","assembleSolidHeatTransferMat","newtonRaphsonResult","worker","feaWorker","isReady","_initWorker","Worker","URL","document","require","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","result","toFixed","getModelInfo","ping","terminate","async","file","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","parseInt","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","level","plotType","plotDivId","meshType","yData","xData","from","lineData","mode","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","l","t","b","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"feascript.cjs.js","sources":["../src/methods/euclideanNormScript.js","../src/utilities/loggingScript.js","../src/methods/linearSystemSolverScript.js","../src/methods/jacobiSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/utilities/helperFunctionsScript.js","../src/solvers/genericBoundaryConditionsScript.js","../src/mesh/basisFunctionsScript.js","../src/mesh/meshGenerationScript.js","../src/methods/numericalIntegrationScript.js","../src/solvers/frontPropagationScript.js","../src/solvers/thermalBoundaryConditionsScript.js","../src/vendor/comlink.mjs","../src/FEAScript.js","../src/solvers/solidHeatTransferScript.js","../src/workers/workerScript.js","../src/index.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.js"],"sourcesContent":["// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to calculate the Euclidean norm of a vector\n * @param {array} vector - The input vector\n * @returns {number} The Euclidean norm of the vector\n */\nexport function euclideanNorm(vector) {\n let norm = 0;\n for (let i = 0; i < vector.length; i++) {\n norm += vector[i] * vector[i];\n }\n norm = Math.sqrt(norm);\n return norm;\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Global logging level\nlet currentLogLevel = \"basic\";\n\n/**\n * Function to set the logging system level\n * @param {string} level - Logging level (basic, debug)\n */\nexport function logSystem(level) {\n if (level !== \"basic\" && level !== \"debug\") {\n console.log(\n \"%c[WARN] Invalid log level: \" + level + \". Using basic instead.\",\n \"color: #FFC107; font-weight: bold;\"\n ); // Yellow for warnings\n currentLogLevel = \"basic\";\n } else {\n currentLogLevel = level;\n basicLog(`Log level set to: ${level}`);\n }\n}\n\n/**\n * Function to log debug messages - only logs if level is 'debug'\n * @param {string} message - Message to log\n */\nexport function debugLog(message) {\n if (currentLogLevel === \"debug\") {\n console.log(\"%c[DEBUG] \" + message, \"color: #2196F3; font-weight: bold;\"); // Blue color for debug\n }\n}\n\n/**\n * Function to log basic information - always logs\n * @param {string} message - Message to log\n */\nexport function basicLog(message) {\n console.log(\"%c[INFO] \" + message, \"color: #4CAF50; font-weight: bold;\"); // Green color for basic info\n}\n\n/**\n * Function to log error messages\n * @param {string} message - Message to log\n */\nexport function errorLog(message) {\n console.log(\"%c[ERROR] \" + message, \"color: #F44336; font-weight: bold;\"); // Red color for errors\n}\n\n/**\n * Function to handle version information and fetch the latest update date and release from GitHub\n */\nexport async function printVersion() {\n basicLog(\"Fetching latest FEAScript version information...\");\n try {\n const commitResponse = await fetch(\"https://api.github.com/repos/FEAScript/FEAScript/commits/main\");\n const commitData = await commitResponse.json();\n const latestCommitDate = new Date(commitData.commit.committer.date).toLocaleString();\n basicLog(`Latest FEAScript update: ${latestCommitDate}`);\n return latestCommitDate;\n } catch (error) {\n errorLog(\"Failed to fetch version information: \" + error);\n return \"Version information unavailable\";\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiSolver } from \"./jacobiSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to solve a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (\"lusolve\" or \"jacobi\")\n * @param {Array} jacobianMatrix - The coefficient matrix\n * @param {Array} residualVector - The right-hand side vector\n * @param {object} [options] - Additional options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum iterations for iterative methods\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance for iterative methods\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - converged: Boolean indicating whether the method converged (for iterative methods)\n * - iterations: Number of iterations performed (for iterative methods)\n */\nexport function solveLinearSystem(solverMethod, jacobianMatrix, residualVector, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n\n let solutionVector = [];\n let converged = true;\n let iterations = 0;\n\n // Solve the linear system based on the specified solver method\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n if (solverMethod === \"lusolve\") {\n // Use LU decomposition method\n solutionVector = math.lusolve(jacobianMatrix, residualVector);\n } else if (solverMethod === \"jacobi\") {\n // Use Jacobi method\n const initialGuess = new Array(residualVector.length).fill(0);\n const jacobiSolverResult = jacobiSolver(jacobianMatrix, residualVector, initialGuess, {\n maxIterations,\n tolerance,\n });\n\n // Log convergence information\n if (jacobiSolverResult.converged) {\n debugLog(`Jacobi method converged in ${jacobiSolverResult.iterations} iterations`);\n } else {\n debugLog(`Jacobi method did not converge after ${jacobiSolverResult.iterations} iterations`);\n }\n\n solutionVector = jacobiSolverResult.solutionVector;\n converged = jacobiSolverResult.converged;\n iterations = jacobiSolverResult.iterations;\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n return { solutionVector, converged, iterations };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method\n * @param {array} jacobianMatrix - The coefficient matrix (must be square)\n * @param {array} residualVector - The right-hand side vector\n * @param {array} initialGuess - Initial guess for solution vector\n * @param {object} [options] - Options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum number of iterations\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\nexport function jacobiSolver(jacobianMatrix, residualVector, initialGuess, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n const n = jacobianMatrix.length; // Size of the square matrix\n let x = [...initialGuess]; // Current solution (starts with initial guess)\n let xNew = new Array(n); // Next iteration's solution\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n // Perform one iteration\n for (let i = 0; i < n; i++) {\n let sum = 0;\n // Calculate sum of jacobianMatrix[i][j] * x[j] for j ≠ i\n for (let j = 0; j < n; j++) {\n if (j !== i) {\n sum += jacobianMatrix[i][j] * x[j];\n }\n }\n // Update xNew[i] using the Jacobi formula\n xNew[i] = (residualVector[i] - sum) / jacobianMatrix[i][i];\n }\n\n // Check convergence\n let maxDiff = 0;\n for (let i = 0; i < n; i++) {\n maxDiff = Math.max(maxDiff, Math.abs(xNew[i] - x[i]));\n }\n\n // Update x for next iteration\n x = [...xNew];\n\n // Successfully converged if maxDiff is less than tolerance\n if (maxDiff < tolerance) {\n return {\n solutionVector: x,\n iterations: iteration + 1,\n converged: true,\n };\n }\n }\n\n // maxIterations were reached without convergence\n return {\n solutionVector: x,\n iterations: maxIterations,\n converged: false,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { euclideanNorm } from \"../methods/euclideanNormScript.js\";\nimport { solveLinearSystem } from \"./linearSystemSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\nimport { calculateSystemSize } from \"../utilities/helperFunctionsScript.js\";\n\n/**\n * Function to solve a system of nonlinear equations using the Newton-Raphson method\n * @param {number} [maxIterations=100] - Maximum number of iterations\n * @param {number} [tolerance=1e-4] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\n\nexport function newtonRaphson(assembleMat, context, maxIterations = 100, tolerance = 1e-4) {\n let errorNorm = 0;\n let converged = false;\n let iterations = 0;\n let deltaX = [];\n let solutionVector = [];\n let jacobianMatrix = [];\n let residualVector = [];\n let nodesCoordinates = {};\n\n // Calculate system size directly from meshConfig\n let totalNodes = calculateSystemSize(context.meshConfig);\n\n // Initialize arrays with proper size\n for (let i = 0; i < totalNodes; i++) {\n deltaX[i] = 0;\n solutionVector[i] = 0;\n }\n\n // Initialize solution from context if available\n if (context.initialSolution && context.initialSolution.length === totalNodes) {\n solutionVector = [...context.initialSolution];\n }\n\n while (iterations < maxIterations && !converged) {\n // Update solution\n for (let i = 0; i < solutionVector.length; i++) {\n solutionVector[i] = Number(solutionVector[i]) + Number(deltaX[i]);\n }\n\n // Compute Jacobian and residual matrices\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleMat(\n context.meshConfig,\n context.boundaryConditions,\n solutionVector, // The solution vector is required in the case of a non-linear equation\n context.eikonalActivationFlag\n ));\n\n // Solve the linear system based on the specified solver method\n const linearSystemResult = solveLinearSystem(context.solverMethod, jacobianMatrix, residualVector);\n deltaX = linearSystemResult.solutionVector;\n\n // Check convergence\n errorNorm = euclideanNorm(deltaX);\n\n // Norm for each iteration\n basicLog(`Newton-Raphson iteration ${iterations + 1}: Error norm = ${errorNorm.toExponential(4)}`);\n\n if (errorNorm <= tolerance) {\n converged = true;\n } else if (errorNorm > 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n nodesCoordinates,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Helper function to calculate system size from mesh configuration\n * @param {object} meshConfig - Mesh configuration object\n * @returns {number} Total number of nodes in the system\n */\nexport function calculateSystemSize(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, elementOrder, parsedMesh } = meshConfig;\n\n if (parsedMesh && parsedMesh.nodesXCoordinates) {\n // For parsed meshes (like from GMSH)\n return parsedMesh.nodesXCoordinates.length;\n } else {\n // For geometry-based meshes\n let nodesX,\n nodesY = 1;\n\n if (elementOrder === \"linear\") {\n nodesX = numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = numElementsY + 1;\n } else if (elementOrder === \"quadratic\") {\n nodesX = 2 * numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = 2 * numElementsY + 1;\n }\n\n return nodesX * nodesY;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n debugLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n if (\n this.numElementsX === null ||\n this.maxX === null ||\n this.numElementsY === null ||\n this.maxY === null\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n \n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\n\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the front propagation matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation (ranges from 0 to 1)\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleFrontPropagationMat(\n meshConfig,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n // TODO: The mesh generation step should be moved outside of the assembleFrontPropagationMat function so that not performed in every Newton-Raphson iteration\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n let solutionDerivX; // The x-derivative of the solution\n let solutionDerivY; // The y-derivative of the solution\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n detJacobian = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n detJacobian = ksiDerivX;\n }\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n // 2D front propagation (eikonal) equation\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n solutionDerivX = 0;\n solutionDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x & y-derivatives of basis functions and x & y-derivatives of the solution\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n // The x-derivative of the solution\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n // The y-derivative of the solution\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector - Viscous term: Add diffusion contribution to stabilize the solution\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n // residualVector - Eikonal term: Add the eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix - Viscous term: Add the Jacobian contribution from the diffusion term\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n // jacobianMatrix - Eikonal term: Add the Jacobian contribution from the eikonal equation\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n (detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)\n ) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n }\n\n // Create an instance of GenericBoundaryConditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions (Robin type)\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n let nodesCoordinates = {};\n let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term - Used in frontPropagationScript\n let newtonRaphsonIterations;\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleSolidHeatTransferMat(\n this.meshConfig,\n this.boundaryConditions\n ));\n\n // Solve the assembled linear system\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n\n // Create context object with all necessary properties\n const context = {\n meshConfig: this.meshConfig,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n nodesCoordinates = newtonRaphsonResult.nodesCoordinates;\n solutionVector = newtonRaphsonResult.solutionVector;\n newtonRaphsonIterations = newtonRaphsonResult.iterations;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the solid heat transfer matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n // 2D solid heat transfer\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Create an instance of ThermalBoundaryConditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.3\";","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","debugLog","message","console","log","basicLog","errorLog","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","math","lusolve","jacobiSolverResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiSolver","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","nodesCoordinates","totalNodes","meshConfig","meshDimension","numElementsX","numElementsY","elementOrder","parsedMesh","nodesXCoordinates","nodesX","nodesY","calculateSystemSize","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","GenericBoundaryConditions","constructor","boundaryElements","nop","this","imposeConstantValueBoundaryConditions","Object","keys","forEach","boundaryKey","value","elementIndex","side","nodeIndex","globalNodeIndex","colIndex","BasisFunctions","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","maxX","maxY","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","undefined","fixedBoundaryElements","boundaryNodePairs","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","generate1DNodalNumbering","findBoundaryElements","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","assembleFrontPropagationMat","eikonalViscousTerm","mesh","nodesCoordinatesAndNumbering","totalElements","xCoordinates","yCoordinates","ksiDerivX","etaDerivX","ksiDerivY","etaDerivY","detJacobian","solutionDerivX","solutionDerivY","localToGlobalMap","basisFunctionDerivX","basisFunctionDerivY","basisFunctions","gaussPointsAndWeights","numNodes","localNodeIndex","gaussPointIndex1","basisFunctionsAndDerivatives","gaussPointIndex2","localNodeIndex1","localToGlobalMap1","localNodeIndex2","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","Error","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","map","fromWireValue","returnValue","parent","slice","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","r","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","arr","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","thermalBoundaryConditions","assembleSolidHeatTransferMat","newtonRaphsonResult","worker","feaWorker","isReady","_initWorker","Worker","URL","document","require","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","result","toFixed","getModelInfo","ping","terminate","async","file","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","parseInt","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","level","plotType","plotDivId","meshType","yData","xData","from","lineData","mode","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","l","t","b","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString"],"mappings":"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"} \ No newline at end of file diff --git a/dist/feascript.esm.js b/dist/feascript.esm.js index 3c6355e..d0a9c3a 100644 --- a/dist/feascript.esm.js +++ b/dist/feascript.esm.js @@ -3,5 +3,5 @@ function e(e){let t=0;for(let n=0;n"object"==typeof e&&null!==e||"function"==typeof e,D=new Map([["proxy",{canHandle:e=>N(e)&&e[$],serialize(e){const{port1:t,port2:n}=new MessageChannel;return x(e,t),[n,[n]]},deserialize:e=>(e.start(),S(e))}],["throw",{canHandle:e=>N(e)&&w in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function x(e,t=globalThis,n=["*"]){t.addEventListener("message",(function s(o){if(!o||!o.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,o.origin))return void console.warn(`Invalid origin '${o.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},o.data),l=(o.data.argumentList||[]).map(W);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=W(o.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[$]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;x(e,n),d=function(e,t){return Y.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[w]:0}}Promise.resolve(d).catch((e=>({value:e,[w]:0}))).then((n=>{const[o,a]=R(n);t.postMessage(Object.assign(Object.assign({},o),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",s),O(t),C in e&&"function"==typeof e[C]&&e[C]())})).catch((e=>{const[n,s]=R({value:new TypeError("Unserializable return value"),[w]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),s)}))})),t.start&&t.start()}function O(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function S(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const s=n.get(t.id);if(s)try{s(t)}finally{n.delete(t.id)}})),T(e,n,[],t)}function A(e){if(e)throw new Error("Proxy has been released and is not useable")}function F(e){return B(e,new Map,{type:"RELEASE"}).then((()=>{O(e)}))}const X=new WeakMap,k="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(X.get(e)||0)-1;X.set(e,t),0===t&&F(e)}));function T(e,t,n=[],s=function(){}){let o=!1;const i=new Proxy(s,{get(s,r){if(A(o),r===v)return()=>{!function(e){k&&k.unregister(e)}(i),F(e),t.clear(),o=!0};if("then"===r){if(0===n.length)return{then:()=>i};const s=B(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(W);return s.then.bind(s)}return T(e,t,[...n,r])},set(s,i,r){A(o);const[a,l]=R(r);return B(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(W)},apply(s,i,r){A(o);const a=n[n.length-1];if(a===M)return B(e,t,{type:"ENDPOINT"}).then(W);if("bind"===a)return T(e,t,n.slice(0,-1));const[l,d]=P(r);return B(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(W)},construct(s,i){A(o);const[r,a]=P(i);return B(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(W)}});return function(e,t){const n=(X.get(t)||0)+1;X.set(t,n),k&&k.register(e,t,e)}(i,e),i}function P(e){const t=e.map(R);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const Y=new WeakMap;function R(e){for(const[t,n]of D)if(n.canHandle(e)){const[s,o]=n.serialize(e);return[{type:"HANDLER",name:t,value:s},o]}return[{type:"RAW",value:e},Y.get(e)||[]]}function W(e){switch(e.type){case"HANDLER":return D.get(e.name).deserialize(e.value);case"RAW":return e.value}}function B(e,t,n,s){return new Promise((o=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,o),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),s)}))}class I{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js",import.meta.url),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=S(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const s=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(s,1e3)};s()}))}async setSolverConfig(e){return await this._ensureReady(),o(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),o("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),o(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),o(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),o("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return o(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}}const q="0.1.2";export{y as FEAScriptModel,I as FEAScriptWorker,q as VERSION,b as importGmshQuadTri,n as logSystem,E as plotSolution,r as printVersion}; + */const $=Symbol("Comlink.proxy"),M=Symbol("Comlink.endpoint"),v=Symbol("Comlink.releaseProxy"),C=Symbol("Comlink.finalizer"),w=Symbol("Comlink.thrown"),N=e=>"object"==typeof e&&null!==e||"function"==typeof e,D=new Map([["proxy",{canHandle:e=>N(e)&&e[$],serialize(e){const{port1:t,port2:n}=new MessageChannel;return x(e,t),[n,[n]]},deserialize:e=>(e.start(),S(e))}],["throw",{canHandle:e=>N(e)&&w in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function x(e,t=globalThis,n=["*"]){t.addEventListener("message",(function s(o){if(!o||!o.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,o.origin))return void console.warn(`Invalid origin '${o.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},o.data),l=(o.data.argumentList||[]).map(W);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=W(o.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[$]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;x(e,n),d=function(e,t){return Y.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[w]:0}}Promise.resolve(d).catch((e=>({value:e,[w]:0}))).then((n=>{const[o,a]=R(n);t.postMessage(Object.assign(Object.assign({},o),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",s),O(t),C in e&&"function"==typeof e[C]&&e[C]())})).catch((e=>{const[n,s]=R({value:new TypeError("Unserializable return value"),[w]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),s)}))})),t.start&&t.start()}function O(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function S(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const s=n.get(t.id);if(s)try{s(t)}finally{n.delete(t.id)}})),T(e,n,[],t)}function A(e){if(e)throw new Error("Proxy has been released and is not useable")}function F(e){return B(e,new Map,{type:"RELEASE"}).then((()=>{O(e)}))}const X=new WeakMap,k="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(X.get(e)||0)-1;X.set(e,t),0===t&&F(e)}));function T(e,t,n=[],s=function(){}){let o=!1;const i=new Proxy(s,{get(s,r){if(A(o),r===v)return()=>{!function(e){k&&k.unregister(e)}(i),F(e),t.clear(),o=!0};if("then"===r){if(0===n.length)return{then:()=>i};const s=B(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(W);return s.then.bind(s)}return T(e,t,[...n,r])},set(s,i,r){A(o);const[a,l]=R(r);return B(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(W)},apply(s,i,r){A(o);const a=n[n.length-1];if(a===M)return B(e,t,{type:"ENDPOINT"}).then(W);if("bind"===a)return T(e,t,n.slice(0,-1));const[l,d]=P(r);return B(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(W)},construct(s,i){A(o);const[r,a]=P(i);return B(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(W)}});return function(e,t){const n=(X.get(t)||0)+1;X.set(t,n),k&&k.register(e,t,e)}(i,e),i}function P(e){const t=e.map(R);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const Y=new WeakMap;function R(e){for(const[t,n]of D)if(n.canHandle(e)){const[s,o]=n.serialize(e);return[{type:"HANDLER",name:t,value:s},o]}return[{type:"RAW",value:e},Y.get(e)||[]]}function W(e){switch(e.type){case"HANDLER":return D.get(e.name).deserialize(e.value);case"RAW":return e.value}}function B(e,t,n,s){return new Promise((o=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,o),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),s)}))}class I{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js",import.meta.url),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=S(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const s=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(s,1e3)};s()}))}async setSolverConfig(e){return await this._ensureReady(),o(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),o("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),o(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),o(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),o("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return o(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}}const q="0.1.3";export{y as FEAScriptModel,I as FEAScriptWorker,q as VERSION,b as importGmshQuadTri,n as logSystem,E as plotSolution,r as printVersion}; //# sourceMappingURL=feascript.esm.js.map diff --git a/dist/feascript.esm.js.map b/dist/feascript.esm.js.map index 4182a19..ac76e61 100644 --- a/dist/feascript.esm.js.map +++ b/dist/feascript.esm.js.map @@ -1 +1 @@ -{"version":3,"file":"feascript.esm.js","sources":["../src/methods/euclideanNormScript.js","../src/utilities/loggingScript.js","../src/methods/linearSystemScript.js","../src/methods/jacobiMethodScript.js","../src/methods/newtonRaphsonScript.js","../src/utilities/helperFunctionsScript.js","../src/solvers/genericBoundaryConditionsScript.js","../src/mesh/basisFunctionsScript.js","../src/mesh/meshGenerationScript.js","../src/methods/numericalIntegrationScript.js","../src/solvers/frontPropagationScript.js","../src/solvers/thermalBoundaryConditionsScript.js","../src/FEAScript.js","../src/solvers/solidHeatTransferScript.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.js","../src/vendor/comlink.mjs","../src/workers/workerScript.js","../src/index.js"],"sourcesContent":["// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to calculate the Euclidean norm of a vector\n * @param {array} vector - The input vector\n * @returns {number} The Euclidean norm of the vector\n */\nexport function euclideanNorm(vector) {\n let norm = 0;\n for (let i = 0; i < vector.length; i++) {\n norm += vector[i] * vector[i];\n }\n norm = Math.sqrt(norm);\n return norm;\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Global logging level\nlet currentLogLevel = \"basic\";\n\n/**\n * Function to set the logging system level\n * @param {string} level - Logging level (basic, debug)\n */\nexport function logSystem(level) {\n if (level !== \"basic\" && level !== \"debug\") {\n console.log(\n \"%c[WARN] Invalid log level: \" + level + \". Using basic instead.\",\n \"color: #FFC107; font-weight: bold;\"\n ); // Yellow for warnings\n currentLogLevel = \"basic\";\n } else {\n currentLogLevel = level;\n basicLog(`Log level set to: ${level}`);\n }\n}\n\n/**\n * Function to log debug messages - only logs if level is 'debug'\n * @param {string} message - Message to log\n */\nexport function debugLog(message) {\n if (currentLogLevel === \"debug\") {\n console.log(\"%c[DEBUG] \" + message, \"color: #2196F3; font-weight: bold;\"); // Blue color for debug\n }\n}\n\n/**\n * Function to log basic information - always logs\n * @param {string} message - Message to log\n */\nexport function basicLog(message) {\n console.log(\"%c[INFO] \" + message, \"color: #4CAF50; font-weight: bold;\"); // Green color for basic info\n}\n\n/**\n * Function to log error messages\n * @param {string} message - Message to log\n */\nexport function errorLog(message) {\n console.log(\"%c[ERROR] \" + message, \"color: #F44336; font-weight: bold;\"); // Red color for errors\n}\n\n/**\n * Function to handle version information and fetch the latest update date and release from GitHub\n */\nexport async function printVersion() {\n basicLog(\"Fetching latest FEAScript version information...\");\n try {\n const commitResponse = await fetch(\"https://api.github.com/repos/FEAScript/FEAScript/commits/main\");\n const commitData = await commitResponse.json();\n const latestCommitDate = new Date(commitData.commit.committer.date).toLocaleString();\n basicLog(`Latest FEAScript update: ${latestCommitDate}`);\n return latestCommitDate;\n } catch (error) {\n errorLog(\"Failed to fetch version information: \" + error);\n return \"Version information unavailable\";\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiMethod } from \"./jacobiMethodScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to solve a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (\"lusolve\" or \"jacobi\")\n * @param {Array} jacobianMatrix - The coefficient matrix\n * @param {Array} residualVector - The right-hand side vector\n * @param {object} [options] - Additional options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum iterations for iterative methods\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance for iterative methods\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - converged: Boolean indicating whether the method converged (for iterative methods)\n * - iterations: Number of iterations performed (for iterative methods)\n */\nexport function solveLinearSystem(solverMethod, jacobianMatrix, residualVector, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n\n let solutionVector = [];\n let converged = true;\n let iterations = 0;\n\n // Solve the linear system based on the specified solver method\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n if (solverMethod === \"lusolve\") {\n // Use LU decomposition method\n solutionVector = math.lusolve(jacobianMatrix, residualVector);\n } else if (solverMethod === \"jacobi\") {\n // Use Jacobi method\n const initialGuess = new Array(residualVector.length).fill(0);\n const jacobiResult = jacobiMethod(jacobianMatrix, residualVector, initialGuess, {\n maxIterations,\n tolerance,\n });\n\n // Log convergence information\n if (jacobiResult.converged) {\n debugLog(`Jacobi method converged in ${jacobiResult.iterations} iterations`);\n } else {\n debugLog(`Jacobi method did not converge after ${jacobiResult.iterations} iterations`);\n }\n\n solutionVector = jacobiResult.solutionVector;\n converged = jacobiResult.converged;\n iterations = jacobiResult.iterations;\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n return { solutionVector, converged, iterations };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method\n * @param {array} jacobianMatrix - The coefficient matrix (must be square)\n * @param {array} residualVector - The right-hand side vector\n * @param {array} initialGuess - Initial guess for solution vector\n * @param {object} [options] - Options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum number of iterations\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\nexport function jacobiMethod(jacobianMatrix, residualVector, initialGuess, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n const n = jacobianMatrix.length; // Size of the square matrix\n let x = [...initialGuess]; // Current solution (starts with initial guess)\n let xNew = new Array(n); // Next iteration's solution\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n // Perform one iteration\n for (let i = 0; i < n; i++) {\n let sum = 0;\n // Calculate sum of jacobianMatrix[i][j] * x[j] for j ≠ i\n for (let j = 0; j < n; j++) {\n if (j !== i) {\n sum += jacobianMatrix[i][j] * x[j];\n }\n }\n // Update xNew[i] using the Jacobi formula\n xNew[i] = (residualVector[i] - sum) / jacobianMatrix[i][i];\n }\n\n // Check convergence\n let maxDiff = 0;\n for (let i = 0; i < n; i++) {\n maxDiff = Math.max(maxDiff, Math.abs(xNew[i] - x[i]));\n }\n\n // Update x for next iteration\n x = [...xNew];\n\n // Successfully converged if maxDiff is less than tolerance\n if (maxDiff < tolerance) {\n return {\n solutionVector: x,\n iterations: iteration + 1,\n converged: true,\n };\n }\n }\n\n // maxIterations were reached without convergence\n return {\n solutionVector: x,\n iterations: maxIterations,\n converged: false,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { euclideanNorm } from \"../methods/euclideanNormScript.js\";\nimport { solveLinearSystem } from \"../methods/linearSystemScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\nimport { calculateSystemSize } from \"../utilities/helperFunctionsScript.js\";\n\n/**\n * Function to solve a system of nonlinear equations using the Newton-Raphson method\n * @param {number} [maxIterations=100] - Maximum number of iterations\n * @param {number} [tolerance=1e-4] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\n\nexport function newtonRaphson(assembleMat, context, maxIterations = 100, tolerance = 1e-4) {\n let errorNorm = 0;\n let converged = false;\n let iterations = 0;\n let deltaX = [];\n let solutionVector = [];\n let jacobianMatrix = [];\n let residualVector = [];\n let nodesCoordinates = {};\n\n // Calculate system size directly from meshConfig\n let totalNodes = calculateSystemSize(context.meshConfig);\n\n // Initialize arrays with proper size\n for (let i = 0; i < totalNodes; i++) {\n deltaX[i] = 0;\n solutionVector[i] = 0;\n }\n\n // Initialize solution from context if available\n if (context.initialSolution && context.initialSolution.length === totalNodes) {\n solutionVector = [...context.initialSolution];\n }\n\n while (iterations < maxIterations && !converged) {\n // Update solution\n for (let i = 0; i < solutionVector.length; i++) {\n solutionVector[i] = Number(solutionVector[i]) + Number(deltaX[i]);\n }\n\n // Compute Jacobian and residual matrices\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleMat(\n context.meshConfig,\n context.boundaryConditions,\n solutionVector, // The solution vector is required in the case of a non-linear equation\n context.eikonalActivationFlag\n ));\n\n // Solve the linear system based on the specified solver method\n const linearSystemResult = solveLinearSystem(context.solverMethod, jacobianMatrix, residualVector);\n deltaX = linearSystemResult.solutionVector;\n\n // Check convergence\n errorNorm = euclideanNorm(deltaX);\n\n // Norm for each iteration\n basicLog(`Newton-Raphson iteration ${iterations + 1}: Error norm = ${errorNorm.toExponential(4)}`);\n\n if (errorNorm <= tolerance) {\n converged = true;\n } else if (errorNorm > 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n nodesCoordinates,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Helper function to calculate system size from mesh configuration\n * @param {object} meshConfig - Mesh configuration object\n * @returns {number} Total number of nodes in the system\n */\nexport function calculateSystemSize(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, elementOrder, parsedMesh } = meshConfig;\n\n if (parsedMesh && parsedMesh.nodesXCoordinates) {\n // For parsed meshes (like from GMSH)\n return parsedMesh.nodesXCoordinates.length;\n } else {\n // For geometry-based meshes\n let nodesX,\n nodesY = 1;\n\n if (elementOrder === \"linear\") {\n nodesX = numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = numElementsY + 1;\n } else if (elementOrder === \"quadratic\") {\n nodesX = 2 * numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = 2 * numElementsY + 1;\n }\n\n return nodesX * nodesY;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n debugLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n if (\n this.numElementsX === null ||\n this.maxX === null ||\n this.numElementsY === null ||\n this.maxY === null\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n \n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\n\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the front propagation matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation (ranges from 0 to 1)\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleFrontPropagationMat(\n meshConfig,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n // TODO: The mesh generation step should be moved outside of the assembleFrontPropagationMat function so that not performed in every Newton-Raphson iteration\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n let solutionDerivX; // The x-derivative of the solution\n let solutionDerivY; // The y-derivative of the solution\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n detJacobian = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n detJacobian = ksiDerivX;\n }\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n // 2D front propagation (eikonal) equation\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n solutionDerivX = 0;\n solutionDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x & y-derivatives of basis functions and x & y-derivatives of the solution\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n // The x-derivative of the solution\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n // The y-derivative of the solution\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector - Viscous term: Add diffusion contribution to stabilize the solution\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n // residualVector - Eikonal term: Add the eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix - Viscous term: Add the Jacobian contribution from the diffusion term\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n // jacobianMatrix - Eikonal term: Add the Jacobian contribution from the eikonal equation\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n (detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)\n ) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n }\n\n // Create an instance of GenericBoundaryConditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions (Robin type)\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiMethod } from \"./methods/jacobiMethodScript.js\";\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n let nodesCoordinates = {};\n let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term - Used in frontPropagationScript\n let newtonRaphsonIterations;\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleSolidHeatTransferMat(\n this.meshConfig,\n this.boundaryConditions\n ));\n\n // Solve the assembled linear system\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n\n // Create context object with all necessary properties\n const context = {\n meshConfig: this.meshConfig,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n nodesCoordinates = newtonRaphsonResult.nodesCoordinates;\n solutionVector = newtonRaphsonResult.solutionVector;\n newtonRaphsonIterations = newtonRaphsonResult.iterations;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the solid heat transfer matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n // 2D solid heat transfer\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Create an instance of ThermalBoundaryConditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.2\";"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","logSystem","level","console","log","basicLog","debugLog","message","errorLog","async","printVersion","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString","error","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","math","lusolve","jacobiResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiMethod","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","nodesCoordinates","totalNodes","meshConfig","meshDimension","numElementsX","numElementsY","elementOrder","parsedMesh","nodesXCoordinates","nodesX","nodesY","calculateSystemSize","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","GenericBoundaryConditions","constructor","boundaryElements","nop","this","imposeConstantValueBoundaryConditions","Object","keys","forEach","boundaryKey","value","elementIndex","side","nodeIndex","globalNodeIndex","colIndex","BasisFunctions","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","maxX","maxY","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","undefined","fixedBoundaryElements","boundaryNodePairs","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","generate1DNodalNumbering","findBoundaryElements","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","assembleFrontPropagationMat","eikonalViscousTerm","mesh","nodesCoordinatesAndNumbering","totalElements","xCoordinates","yCoordinates","ksiDerivX","etaDerivX","ksiDerivY","etaDerivY","detJacobian","solutionDerivX","solutionDerivY","localToGlobalMap","basisFunctionDerivX","basisFunctionDerivY","basisFunctions","gaussPointsAndWeights","numNodes","localNodeIndex","gaussPointIndex1","basisFunctionsAndDerivatives","gaussPointIndex2","localNodeIndex1","localToGlobalMap1","localNodeIndex2","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","FEAScriptModel","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","Error","thermalBoundaryConditions","assembleSolidHeatTransferMat","newtonRaphsonResult","importGmshQuadTri","file","result","gmshV","ascii","fltBytes","lines","text","split","map","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","test","parseInt","slice","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","plotSolution","plotType","plotDivId","meshType","yData","arr","xData","from","lineData","mode","type","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","l","r","t","b","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","val","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","isAllowedOrigin","warn","id","path","argumentList","fromWireValue","returnValue","parent","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","FEAScriptWorker","worker","feaWorker","isReady","_initWorker","Worker","URL","url","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","toFixed","getModelInfo","ping","terminate","VERSION"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"feascript.esm.js","sources":["../src/methods/euclideanNormScript.js","../src/utilities/loggingScript.js","../src/methods/linearSystemSolverScript.js","../src/methods/jacobiSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/utilities/helperFunctionsScript.js","../src/solvers/genericBoundaryConditionsScript.js","../src/mesh/basisFunctionsScript.js","../src/mesh/meshGenerationScript.js","../src/methods/numericalIntegrationScript.js","../src/solvers/frontPropagationScript.js","../src/solvers/thermalBoundaryConditionsScript.js","../src/FEAScript.js","../src/solvers/solidHeatTransferScript.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.js","../src/vendor/comlink.mjs","../src/workers/workerScript.js","../src/index.js"],"sourcesContent":["// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to calculate the Euclidean norm of a vector\n * @param {array} vector - The input vector\n * @returns {number} The Euclidean norm of the vector\n */\nexport function euclideanNorm(vector) {\n let norm = 0;\n for (let i = 0; i < vector.length; i++) {\n norm += vector[i] * vector[i];\n }\n norm = Math.sqrt(norm);\n return norm;\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Global logging level\nlet currentLogLevel = \"basic\";\n\n/**\n * Function to set the logging system level\n * @param {string} level - Logging level (basic, debug)\n */\nexport function logSystem(level) {\n if (level !== \"basic\" && level !== \"debug\") {\n console.log(\n \"%c[WARN] Invalid log level: \" + level + \". Using basic instead.\",\n \"color: #FFC107; font-weight: bold;\"\n ); // Yellow for warnings\n currentLogLevel = \"basic\";\n } else {\n currentLogLevel = level;\n basicLog(`Log level set to: ${level}`);\n }\n}\n\n/**\n * Function to log debug messages - only logs if level is 'debug'\n * @param {string} message - Message to log\n */\nexport function debugLog(message) {\n if (currentLogLevel === \"debug\") {\n console.log(\"%c[DEBUG] \" + message, \"color: #2196F3; font-weight: bold;\"); // Blue color for debug\n }\n}\n\n/**\n * Function to log basic information - always logs\n * @param {string} message - Message to log\n */\nexport function basicLog(message) {\n console.log(\"%c[INFO] \" + message, \"color: #4CAF50; font-weight: bold;\"); // Green color for basic info\n}\n\n/**\n * Function to log error messages\n * @param {string} message - Message to log\n */\nexport function errorLog(message) {\n console.log(\"%c[ERROR] \" + message, \"color: #F44336; font-weight: bold;\"); // Red color for errors\n}\n\n/**\n * Function to handle version information and fetch the latest update date and release from GitHub\n */\nexport async function printVersion() {\n basicLog(\"Fetching latest FEAScript version information...\");\n try {\n const commitResponse = await fetch(\"https://api.github.com/repos/FEAScript/FEAScript/commits/main\");\n const commitData = await commitResponse.json();\n const latestCommitDate = new Date(commitData.commit.committer.date).toLocaleString();\n basicLog(`Latest FEAScript update: ${latestCommitDate}`);\n return latestCommitDate;\n } catch (error) {\n errorLog(\"Failed to fetch version information: \" + error);\n return \"Version information unavailable\";\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiSolver } from \"./jacobiSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to solve a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (\"lusolve\" or \"jacobi\")\n * @param {Array} jacobianMatrix - The coefficient matrix\n * @param {Array} residualVector - The right-hand side vector\n * @param {object} [options] - Additional options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum iterations for iterative methods\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance for iterative methods\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - converged: Boolean indicating whether the method converged (for iterative methods)\n * - iterations: Number of iterations performed (for iterative methods)\n */\nexport function solveLinearSystem(solverMethod, jacobianMatrix, residualVector, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n\n let solutionVector = [];\n let converged = true;\n let iterations = 0;\n\n // Solve the linear system based on the specified solver method\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n if (solverMethod === \"lusolve\") {\n // Use LU decomposition method\n solutionVector = math.lusolve(jacobianMatrix, residualVector);\n } else if (solverMethod === \"jacobi\") {\n // Use Jacobi method\n const initialGuess = new Array(residualVector.length).fill(0);\n const jacobiSolverResult = jacobiSolver(jacobianMatrix, residualVector, initialGuess, {\n maxIterations,\n tolerance,\n });\n\n // Log convergence information\n if (jacobiSolverResult.converged) {\n debugLog(`Jacobi method converged in ${jacobiSolverResult.iterations} iterations`);\n } else {\n debugLog(`Jacobi method did not converge after ${jacobiSolverResult.iterations} iterations`);\n }\n\n solutionVector = jacobiSolverResult.solutionVector;\n converged = jacobiSolverResult.converged;\n iterations = jacobiSolverResult.iterations;\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n return { solutionVector, converged, iterations };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method\n * @param {array} jacobianMatrix - The coefficient matrix (must be square)\n * @param {array} residualVector - The right-hand side vector\n * @param {array} initialGuess - Initial guess for solution vector\n * @param {object} [options] - Options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum number of iterations\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\nexport function jacobiSolver(jacobianMatrix, residualVector, initialGuess, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n const n = jacobianMatrix.length; // Size of the square matrix\n let x = [...initialGuess]; // Current solution (starts with initial guess)\n let xNew = new Array(n); // Next iteration's solution\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n // Perform one iteration\n for (let i = 0; i < n; i++) {\n let sum = 0;\n // Calculate sum of jacobianMatrix[i][j] * x[j] for j ≠ i\n for (let j = 0; j < n; j++) {\n if (j !== i) {\n sum += jacobianMatrix[i][j] * x[j];\n }\n }\n // Update xNew[i] using the Jacobi formula\n xNew[i] = (residualVector[i] - sum) / jacobianMatrix[i][i];\n }\n\n // Check convergence\n let maxDiff = 0;\n for (let i = 0; i < n; i++) {\n maxDiff = Math.max(maxDiff, Math.abs(xNew[i] - x[i]));\n }\n\n // Update x for next iteration\n x = [...xNew];\n\n // Successfully converged if maxDiff is less than tolerance\n if (maxDiff < tolerance) {\n return {\n solutionVector: x,\n iterations: iteration + 1,\n converged: true,\n };\n }\n }\n\n // maxIterations were reached without convergence\n return {\n solutionVector: x,\n iterations: maxIterations,\n converged: false,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { euclideanNorm } from \"../methods/euclideanNormScript.js\";\nimport { solveLinearSystem } from \"./linearSystemSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\nimport { calculateSystemSize } from \"../utilities/helperFunctionsScript.js\";\n\n/**\n * Function to solve a system of nonlinear equations using the Newton-Raphson method\n * @param {number} [maxIterations=100] - Maximum number of iterations\n * @param {number} [tolerance=1e-4] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\n\nexport function newtonRaphson(assembleMat, context, maxIterations = 100, tolerance = 1e-4) {\n let errorNorm = 0;\n let converged = false;\n let iterations = 0;\n let deltaX = [];\n let solutionVector = [];\n let jacobianMatrix = [];\n let residualVector = [];\n let nodesCoordinates = {};\n\n // Calculate system size directly from meshConfig\n let totalNodes = calculateSystemSize(context.meshConfig);\n\n // Initialize arrays with proper size\n for (let i = 0; i < totalNodes; i++) {\n deltaX[i] = 0;\n solutionVector[i] = 0;\n }\n\n // Initialize solution from context if available\n if (context.initialSolution && context.initialSolution.length === totalNodes) {\n solutionVector = [...context.initialSolution];\n }\n\n while (iterations < maxIterations && !converged) {\n // Update solution\n for (let i = 0; i < solutionVector.length; i++) {\n solutionVector[i] = Number(solutionVector[i]) + Number(deltaX[i]);\n }\n\n // Compute Jacobian and residual matrices\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleMat(\n context.meshConfig,\n context.boundaryConditions,\n solutionVector, // The solution vector is required in the case of a non-linear equation\n context.eikonalActivationFlag\n ));\n\n // Solve the linear system based on the specified solver method\n const linearSystemResult = solveLinearSystem(context.solverMethod, jacobianMatrix, residualVector);\n deltaX = linearSystemResult.solutionVector;\n\n // Check convergence\n errorNorm = euclideanNorm(deltaX);\n\n // Norm for each iteration\n basicLog(`Newton-Raphson iteration ${iterations + 1}: Error norm = ${errorNorm.toExponential(4)}`);\n\n if (errorNorm <= tolerance) {\n converged = true;\n } else if (errorNorm > 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n nodesCoordinates,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Helper function to calculate system size from mesh configuration\n * @param {object} meshConfig - Mesh configuration object\n * @returns {number} Total number of nodes in the system\n */\nexport function calculateSystemSize(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, elementOrder, parsedMesh } = meshConfig;\n\n if (parsedMesh && parsedMesh.nodesXCoordinates) {\n // For parsed meshes (like from GMSH)\n return parsedMesh.nodesXCoordinates.length;\n } else {\n // For geometry-based meshes\n let nodesX,\n nodesY = 1;\n\n if (elementOrder === \"linear\") {\n nodesX = numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = numElementsY + 1;\n } else if (elementOrder === \"quadratic\") {\n nodesX = 2 * numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = 2 * numElementsY + 1;\n }\n\n return nodesX * nodesY;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n debugLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n if (\n this.numElementsX === null ||\n this.maxX === null ||\n this.numElementsY === null ||\n this.maxY === null\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n \n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\n\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the front propagation matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation (ranges from 0 to 1)\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleFrontPropagationMat(\n meshConfig,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n // TODO: The mesh generation step should be moved outside of the assembleFrontPropagationMat function so that not performed in every Newton-Raphson iteration\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n let solutionDerivX; // The x-derivative of the solution\n let solutionDerivY; // The y-derivative of the solution\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n detJacobian = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n detJacobian = ksiDerivX;\n }\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n // 2D front propagation (eikonal) equation\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n solutionDerivX = 0;\n solutionDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x & y-derivatives of basis functions and x & y-derivatives of the solution\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n // The x-derivative of the solution\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n // The y-derivative of the solution\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector - Viscous term: Add diffusion contribution to stabilize the solution\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n // residualVector - Eikonal term: Add the eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix - Viscous term: Add the Jacobian contribution from the diffusion term\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n // jacobianMatrix - Eikonal term: Add the Jacobian contribution from the eikonal equation\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n (detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)\n ) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n }\n\n // Create an instance of GenericBoundaryConditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions (Robin type)\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n let nodesCoordinates = {};\n let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term - Used in frontPropagationScript\n let newtonRaphsonIterations;\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleSolidHeatTransferMat(\n this.meshConfig,\n this.boundaryConditions\n ));\n\n // Solve the assembled linear system\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n\n // Create context object with all necessary properties\n const context = {\n meshConfig: this.meshConfig,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n nodesCoordinates = newtonRaphsonResult.nodesCoordinates;\n solutionVector = newtonRaphsonResult.solutionVector;\n newtonRaphsonIterations = newtonRaphsonResult.iterations;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the solid heat transfer matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n // 2D solid heat transfer\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Create an instance of ThermalBoundaryConditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.3\";"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","logSystem","level","console","log","basicLog","debugLog","message","errorLog","async","printVersion","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString","error","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","math","lusolve","jacobiSolverResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiSolver","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","nodesCoordinates","totalNodes","meshConfig","meshDimension","numElementsX","numElementsY","elementOrder","parsedMesh","nodesXCoordinates","nodesX","nodesY","calculateSystemSize","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","GenericBoundaryConditions","constructor","boundaryElements","nop","this","imposeConstantValueBoundaryConditions","Object","keys","forEach","boundaryKey","value","elementIndex","side","nodeIndex","globalNodeIndex","colIndex","BasisFunctions","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","maxX","maxY","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","undefined","fixedBoundaryElements","boundaryNodePairs","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","generate1DNodalNumbering","findBoundaryElements","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","assembleFrontPropagationMat","eikonalViscousTerm","mesh","nodesCoordinatesAndNumbering","totalElements","xCoordinates","yCoordinates","ksiDerivX","etaDerivX","ksiDerivY","etaDerivY","detJacobian","solutionDerivX","solutionDerivY","localToGlobalMap","basisFunctionDerivX","basisFunctionDerivY","basisFunctions","gaussPointsAndWeights","numNodes","localNodeIndex","gaussPointIndex1","basisFunctionsAndDerivatives","gaussPointIndex2","localNodeIndex1","localToGlobalMap1","localNodeIndex2","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","FEAScriptModel","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","Error","thermalBoundaryConditions","assembleSolidHeatTransferMat","newtonRaphsonResult","importGmshQuadTri","file","result","gmshV","ascii","fltBytes","lines","text","split","map","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","test","parseInt","slice","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","plotSolution","plotType","plotDivId","meshType","yData","arr","xData","from","lineData","mode","type","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","l","r","t","b","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","val","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","isAllowedOrigin","warn","id","path","argumentList","fromWireValue","returnValue","parent","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","FEAScriptWorker","worker","feaWorker","isReady","_initWorker","Worker","URL","url","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","toFixed","getModelInfo","ping","terminate","VERSION"],"mappings":"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"} \ No newline at end of file diff --git a/dist/feascript.umd.js b/dist/feascript.umd.js index dc4058b..3af0cfe 100644 --- a/dist/feascript.umd.js +++ b/dist/feascript.umd.js @@ -4,5 +4,5 @@ * Copyright 2019 Google LLC * SPDX-License-Identifier: Apache-2.0 */ -const g=Symbol("Comlink.proxy"),y=Symbol("Comlink.endpoint"),b=Symbol("Comlink.releaseProxy"),E=Symbol("Comlink.finalizer"),$=Symbol("Comlink.thrown"),M=e=>"object"==typeof e&&null!==e||"function"==typeof e,v=new Map([["proxy",{canHandle:e=>M(e)&&e[g],serialize(e){const{port1:t,port2:n}=new MessageChannel;return C(e,t),[n,[n]]},deserialize:e=>(e.start(),S(e))}],["throw",{canHandle:e=>M(e)&&$ in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function C(e,t=globalThis,n=["*"]){t.addEventListener("message",(function o(s){if(!s||!s.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,s.origin))return void console.warn(`Invalid origin '${s.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},s.data),l=(s.data.argumentList||[]).map(T);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=T(s.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[g]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;C(e,n),d=function(e,t){return X.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[$]:0}}Promise.resolve(d).catch((e=>({value:e,[$]:0}))).then((n=>{const[s,a]=k(n);t.postMessage(Object.assign(Object.assign({},s),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",o),w(t),E in e&&"function"==typeof e[E]&&e[E]())})).catch((e=>{const[n,o]=k({value:new TypeError("Unserializable return value"),[$]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),o)}))})),t.start&&t.start()}function w(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function S(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const o=n.get(t.id);if(o)try{o(t)}finally{n.delete(t.id)}})),A(e,n,[],t)}function N(e){if(e)throw new Error("Proxy has been released and is not useable")}function x(e){return P(e,new Map,{type:"RELEASE"}).then((()=>{w(e)}))}const O=new WeakMap,D="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(O.get(e)||0)-1;O.set(e,t),0===t&&x(e)}));function A(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(N(s),r===b)return()=>{!function(e){D&&D.unregister(e)}(i),x(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=P(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(T);return o.then.bind(o)}return A(e,t,[...n,r])},set(o,i,r){N(s);const[a,l]=k(r);return P(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(T)},apply(o,i,r){N(s);const a=n[n.length-1];if(a===y)return P(e,t,{type:"ENDPOINT"}).then(T);if("bind"===a)return A(e,t,n.slice(0,-1));const[l,d]=F(r);return P(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(T)},construct(o,i){N(s);const[r,a]=F(i);return P(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(T)}});return function(e,t){const n=(O.get(t)||0)+1;O.set(t,n),D&&D.register(e,t,e)}(i,e),i}function F(e){const t=e.map(k);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const X=new WeakMap;function k(e){for(const[t,n]of v)if(n.canHandle(e)){const[o,s]=n.serialize(e);return[{type:"HANDLER",name:t,value:o},s]}return[{type:"RAW",value:e},X.get(e)||[]]}function T(e){switch(e.type){case"HANDLER":return v.get(e.name).deserialize(e.value);case"RAW":return e.value}}function P(e,t,n,o){return new Promise((s=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,s),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),o)}))}e.FEAScriptModel=class{constructor(){this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",s("FEAScriptModel instance created")}setSolverConfig(e){this.solverConfig=e,o(`Solver config set to: ${e}`)}setMeshConfig(e){this.meshConfig=e,o(`Mesh config set with dimensions: ${e.meshDimension}`)}addBoundaryCondition(e,t){this.boundaryConditions[e]=t,o(`Boundary condition added for boundary: ${e}, type: ${t[0]}`)}setSolverMethod(e){this.solverMethod=e,o(`Solver method set to: ${e}`)}solve(){if(!this.solverConfig||!this.meshConfig||!this.boundaryConditions){const e="Solver config, mesh config, and boundary conditions must be set before solving.";throw console.error(e),new Error(e)}let e=[],t=[],n=[],l=[],m={};if(s("Beginning solving process..."),console.time("totalSolvingTime"),"solidHeatTransferScript"===this.solverConfig){s(`Using solver: ${this.solverConfig}`),({jacobianMatrix:e,residualVector:t,nodesCoordinates:m}=function(e,t){s("Starting solid heat transfer matrix assembly...");const{meshDimension:n,numElementsX:r,numElementsY:a,maxX:l,maxY:m,elementOrder:f,parsedMesh:g}=e;let y;o("Generating mesh..."),"1D"===n?y=new h({numElementsX:r,maxX:l,elementOrder:f,parsedMesh:g}):"2D"===n?y=new u({numElementsX:r,maxX:l,numElementsY:a,maxY:m,elementOrder:f,parsedMesh:g}):i("Mesh dimension must be either '1D' or '2D'.");const b=y.boundaryElementsProcessed?y.parsedMesh:y.generateMesh();let E,$,M=b.nodesXCoordinates,v=b.nodesYCoordinates,C=b.totalNodesX,w=b.totalNodesY,S=b.nodalNumbering,N=b.boundaryElements;null!=g?(E=S.length,$=M.length,o(`Using parsed mesh with ${E} elements and ${$} nodes`)):(E=r*("2D"===n?a:1),$=C*("2D"===n?w:1),o(`Using mesh generated from geometry with ${E} elements and ${$} nodes`));let x,O,D,A,F,X,k,T=[],P=[],Y=[],R=[],W=[],I=[],B=[],j=[],q=[],V=[];for(let e=0;e<$;e++){q[e]=0,V.push([]);for(let t=0;t<$;t++)V[e][t]=0}const L=new d({meshDimension:n,elementOrder:f});let G=new c({meshDimension:n,elementOrder:f}).getGaussPointsAndWeights();P=G.gaussPoints,Y=G.gaussWeights;const U=S[0].length;for(let e=0;e0&&(i.initialSolution=[...n]);const s=a(f,i,100,1e-4);e=s.jacobianMatrix,t=s.residualVector,m=s.nodesCoordinates,n=s.solutionVector,o+=.2}}return console.timeEnd("totalSolvingTime"),s("Solving process completed"),{solutionVector:n,nodesCoordinates:m}}},e.FEAScriptWorker=class{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js","undefined"==typeof document&&"undefined"==typeof location?new(require("url").URL)("file:"+__filename).href:"undefined"==typeof document?location.href:document.currentScript&&"SCRIPT"===document.currentScript.tagName.toUpperCase()&&document.currentScript.src||new URL("feascript.umd.js",document.baseURI).href),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=S(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const o=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(o,1e3)};o()}))}async setSolverConfig(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),s("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),s(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),s("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return s(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}},e.VERSION="0.1.2",e.importGmshQuadTri=async e=>{let t={nodesXCoordinates:[],nodesYCoordinates:[],nodalNumbering:{quadElements:[],triangleElements:[]},boundaryElements:[],boundaryConditions:[],boundaryNodePairs:{},gmshV:0,ascii:!1,fltBytes:"8",totalNodesX:0,totalNodesY:0,physicalPropMap:[],elementTypes:{}},n=(await e.text()).split("\n").map((e=>e.trim())).filter((e=>""!==e&&" "!==e)),s="",i=0,r=0,a=0,l=0,d={numNodes:0},m=0,h=[],u=0,c=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},g=0,y={};for(;i""!==e));if("meshFormat"===s)t.gmshV=parseFloat(o[0]),t.ascii="0"===o[1],t.fltBytes=o[2];else if("physicalNames"===s){if(o.length>=3){if(!/^\d+$/.test(o[0])){i++;continue}const e=parseInt(o[0],10),n=parseInt(o[1],10);let s=o.slice(2).join(" ");s=s.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:n,dimension:e,name:s})}}else if("nodes"===s){if(0===r){r=parseInt(o[0],10),a=parseInt(o[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;y[n]||(y[n]=[]),y[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);g++,g===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=y[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),o(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t},e.logSystem=function(e){"basic"!==e&&"debug"!==e?(console.log("%c[WARN] Invalid log level: "+e+". Using basic instead.","color: #FFC107; font-weight: bold;"),n="basic"):(n=e,s(`Log level set to: ${e}`))},e.plotSolution=function(e,t,n,o,s,i,r="structured"){const{nodesXCoordinates:a,nodesYCoordinates:l}=t;if("1D"===o&&"line"===s){let t;t=e.length>0&&Array.isArray(e[0])?e.map((e=>e[0])):e;let o=Array.from(a),s={x:o,y:t,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},r=Math.min(window.innerWidth,700),l=Math.max(...o),d=r/l,m={title:`line plot - ${n}`,width:Math.max(d*l,400),height:350,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:70,r:40,t:50,b:50}};Plotly.newPlot(i,[s],m,{responsive:!0})}else if("2D"===o&&"contour"===s){const t="structured"===r,o=new Set(a).size,d=new Set(l).size;let m;m=Array.isArray(e[0])?e.map((e=>e[0])):e;let h=Math.min(window.innerWidth,700),u=Math.max(...a),c=Math.max(...l)/u,f=Math.min(h,600),p={title:`${s} plot - ${n}`,width:f,height:f*c*.8,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"};if(t){const t=o,n=d;math.reshape(Array.from(a),[t,n]);let s=math.reshape(Array.from(l),[t,n]),r=math.reshape(Array.from(e),[t,n]),m=math.transpose(r),h=[];for(let e=0;e"object"==typeof e&&null!==e||"function"==typeof e,v=new Map([["proxy",{canHandle:e=>M(e)&&e[g],serialize(e){const{port1:t,port2:n}=new MessageChannel;return C(e,t),[n,[n]]},deserialize:e=>(e.start(),S(e))}],["throw",{canHandle:e=>M(e)&&$ in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function C(e,t=globalThis,n=["*"]){t.addEventListener("message",(function o(s){if(!s||!s.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,s.origin))return void console.warn(`Invalid origin '${s.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},s.data),l=(s.data.argumentList||[]).map(T);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=T(s.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[g]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;C(e,n),d=function(e,t){return X.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[$]:0}}Promise.resolve(d).catch((e=>({value:e,[$]:0}))).then((n=>{const[s,a]=k(n);t.postMessage(Object.assign(Object.assign({},s),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",o),w(t),E in e&&"function"==typeof e[E]&&e[E]())})).catch((e=>{const[n,o]=k({value:new TypeError("Unserializable return value"),[$]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),o)}))})),t.start&&t.start()}function w(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function S(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const o=n.get(t.id);if(o)try{o(t)}finally{n.delete(t.id)}})),A(e,n,[],t)}function N(e){if(e)throw new Error("Proxy has been released and is not useable")}function x(e){return P(e,new Map,{type:"RELEASE"}).then((()=>{w(e)}))}const O=new WeakMap,D="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(O.get(e)||0)-1;O.set(e,t),0===t&&x(e)}));function A(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(N(s),r===b)return()=>{!function(e){D&&D.unregister(e)}(i),x(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=P(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(T);return o.then.bind(o)}return A(e,t,[...n,r])},set(o,i,r){N(s);const[a,l]=k(r);return P(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(T)},apply(o,i,r){N(s);const a=n[n.length-1];if(a===y)return P(e,t,{type:"ENDPOINT"}).then(T);if("bind"===a)return A(e,t,n.slice(0,-1));const[l,d]=F(r);return P(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(T)},construct(o,i){N(s);const[r,a]=F(i);return P(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(T)}});return function(e,t){const n=(O.get(t)||0)+1;O.set(t,n),D&&D.register(e,t,e)}(i,e),i}function F(e){const t=e.map(k);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const X=new WeakMap;function k(e){for(const[t,n]of v)if(n.canHandle(e)){const[o,s]=n.serialize(e);return[{type:"HANDLER",name:t,value:o},s]}return[{type:"RAW",value:e},X.get(e)||[]]}function T(e){switch(e.type){case"HANDLER":return v.get(e.name).deserialize(e.value);case"RAW":return e.value}}function P(e,t,n,o){return new Promise((s=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,s),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),o)}))}e.FEAScriptModel=class{constructor(){this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",s("FEAScriptModel instance created")}setSolverConfig(e){this.solverConfig=e,o(`Solver config set to: ${e}`)}setMeshConfig(e){this.meshConfig=e,o(`Mesh config set with dimensions: ${e.meshDimension}`)}addBoundaryCondition(e,t){this.boundaryConditions[e]=t,o(`Boundary condition added for boundary: ${e}, type: ${t[0]}`)}setSolverMethod(e){this.solverMethod=e,o(`Solver method set to: ${e}`)}solve(){if(!this.solverConfig||!this.meshConfig||!this.boundaryConditions){const e="Solver config, mesh config, and boundary conditions must be set before solving.";throw console.error(e),new Error(e)}let e=[],t=[],n=[],l=[],m={};if(s("Beginning solving process..."),console.time("totalSolvingTime"),"solidHeatTransferScript"===this.solverConfig){s(`Using solver: ${this.solverConfig}`),({jacobianMatrix:e,residualVector:t,nodesCoordinates:m}=function(e,t){s("Starting solid heat transfer matrix assembly...");const{meshDimension:n,numElementsX:r,numElementsY:a,maxX:l,maxY:m,elementOrder:f,parsedMesh:g}=e;let y;o("Generating mesh..."),"1D"===n?y=new h({numElementsX:r,maxX:l,elementOrder:f,parsedMesh:g}):"2D"===n?y=new u({numElementsX:r,maxX:l,numElementsY:a,maxY:m,elementOrder:f,parsedMesh:g}):i("Mesh dimension must be either '1D' or '2D'.");const b=y.boundaryElementsProcessed?y.parsedMesh:y.generateMesh();let E,$,M=b.nodesXCoordinates,v=b.nodesYCoordinates,C=b.totalNodesX,w=b.totalNodesY,S=b.nodalNumbering,N=b.boundaryElements;null!=g?(E=S.length,$=M.length,o(`Using parsed mesh with ${E} elements and ${$} nodes`)):(E=r*("2D"===n?a:1),$=C*("2D"===n?w:1),o(`Using mesh generated from geometry with ${E} elements and ${$} nodes`));let x,O,D,A,F,X,k,T=[],P=[],Y=[],R=[],W=[],I=[],B=[],j=[],q=[],V=[];for(let e=0;e<$;e++){q[e]=0,V.push([]);for(let t=0;t<$;t++)V[e][t]=0}const L=new d({meshDimension:n,elementOrder:f});let G=new c({meshDimension:n,elementOrder:f}).getGaussPointsAndWeights();P=G.gaussPoints,Y=G.gaussWeights;const U=S[0].length;for(let e=0;e0&&(i.initialSolution=[...n]);const s=a(f,i,100,1e-4);e=s.jacobianMatrix,t=s.residualVector,m=s.nodesCoordinates,n=s.solutionVector,o+=.2}}return console.timeEnd("totalSolvingTime"),s("Solving process completed"),{solutionVector:n,nodesCoordinates:m}}},e.FEAScriptWorker=class{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js","undefined"==typeof document&&"undefined"==typeof location?new(require("url").URL)("file:"+__filename).href:"undefined"==typeof document?location.href:document.currentScript&&"SCRIPT"===document.currentScript.tagName.toUpperCase()&&document.currentScript.src||new URL("feascript.umd.js",document.baseURI).href),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=S(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const o=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(o,1e3)};o()}))}async setSolverConfig(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),s("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),s(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),s("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return s(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}},e.VERSION="0.1.3",e.importGmshQuadTri=async e=>{let t={nodesXCoordinates:[],nodesYCoordinates:[],nodalNumbering:{quadElements:[],triangleElements:[]},boundaryElements:[],boundaryConditions:[],boundaryNodePairs:{},gmshV:0,ascii:!1,fltBytes:"8",totalNodesX:0,totalNodesY:0,physicalPropMap:[],elementTypes:{}},n=(await e.text()).split("\n").map((e=>e.trim())).filter((e=>""!==e&&" "!==e)),s="",i=0,r=0,a=0,l=0,d={numNodes:0},m=0,h=[],u=0,c=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},g=0,y={};for(;i""!==e));if("meshFormat"===s)t.gmshV=parseFloat(o[0]),t.ascii="0"===o[1],t.fltBytes=o[2];else if("physicalNames"===s){if(o.length>=3){if(!/^\d+$/.test(o[0])){i++;continue}const e=parseInt(o[0],10),n=parseInt(o[1],10);let s=o.slice(2).join(" ");s=s.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:n,dimension:e,name:s})}}else if("nodes"===s){if(0===r){r=parseInt(o[0],10),a=parseInt(o[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;y[n]||(y[n]=[]),y[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);g++,g===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=y[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),o(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t},e.logSystem=function(e){"basic"!==e&&"debug"!==e?(console.log("%c[WARN] Invalid log level: "+e+". Using basic instead.","color: #FFC107; font-weight: bold;"),n="basic"):(n=e,s(`Log level set to: ${e}`))},e.plotSolution=function(e,t,n,o,s,i,r="structured"){const{nodesXCoordinates:a,nodesYCoordinates:l}=t;if("1D"===o&&"line"===s){let t;t=e.length>0&&Array.isArray(e[0])?e.map((e=>e[0])):e;let o=Array.from(a),s={x:o,y:t,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},r=Math.min(window.innerWidth,700),l=Math.max(...o),d=r/l,m={title:`line plot - ${n}`,width:Math.max(d*l,400),height:350,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:70,r:40,t:50,b:50}};Plotly.newPlot(i,[s],m,{responsive:!0})}else if("2D"===o&&"contour"===s){const t="structured"===r,o=new Set(a).size,d=new Set(l).size;let m;m=Array.isArray(e[0])?e.map((e=>e[0])):e;let h=Math.min(window.innerWidth,700),u=Math.max(...a),c=Math.max(...l)/u,f=Math.min(h,600),p={title:`${s} plot - ${n}`,width:f,height:f*c*.8,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"};if(t){const t=o,n=d;math.reshape(Array.from(a),[t,n]);let s=math.reshape(Array.from(l),[t,n]),r=math.reshape(Array.from(e),[t,n]),m=math.transpose(r),h=[];for(let e=0;e 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n nodesCoordinates,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Helper function to calculate system size from mesh configuration\n * @param {object} meshConfig - Mesh configuration object\n * @returns {number} Total number of nodes in the system\n */\nexport function calculateSystemSize(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, elementOrder, parsedMesh } = meshConfig;\n\n if (parsedMesh && parsedMesh.nodesXCoordinates) {\n // For parsed meshes (like from GMSH)\n return parsedMesh.nodesXCoordinates.length;\n } else {\n // For geometry-based meshes\n let nodesX,\n nodesY = 1;\n\n if (elementOrder === \"linear\") {\n nodesX = numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = numElementsY + 1;\n } else if (elementOrder === \"quadratic\") {\n nodesX = 2 * numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = 2 * numElementsY + 1;\n }\n\n return nodesX * nodesY;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n debugLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n if (\n this.numElementsX === null ||\n this.maxX === null ||\n this.numElementsY === null ||\n this.maxY === null\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n \n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\n\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the front propagation matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation (ranges from 0 to 1)\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleFrontPropagationMat(\n meshConfig,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n // TODO: The mesh generation step should be moved outside of the assembleFrontPropagationMat function so that not performed in every Newton-Raphson iteration\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n let solutionDerivX; // The x-derivative of the solution\n let solutionDerivY; // The y-derivative of the solution\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n detJacobian = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n detJacobian = ksiDerivX;\n }\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n // 2D front propagation (eikonal) equation\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n solutionDerivX = 0;\n solutionDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x & y-derivatives of basis functions and x & y-derivatives of the solution\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n // The x-derivative of the solution\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n // The y-derivative of the solution\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector - Viscous term: Add diffusion contribution to stabilize the solution\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n // residualVector - Eikonal term: Add the eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix - Viscous term: Add the Jacobian contribution from the diffusion term\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n // jacobianMatrix - Eikonal term: Add the Jacobian contribution from the eikonal equation\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n (detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)\n ) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n }\n\n // Create an instance of GenericBoundaryConditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions (Robin type)\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiMethod } from \"./methods/jacobiMethodScript.js\";\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n let nodesCoordinates = {};\n let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term - Used in frontPropagationScript\n let newtonRaphsonIterations;\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleSolidHeatTransferMat(\n this.meshConfig,\n this.boundaryConditions\n ));\n\n // Solve the assembled linear system\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n\n // Create context object with all necessary properties\n const context = {\n meshConfig: this.meshConfig,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n nodesCoordinates = newtonRaphsonResult.nodesCoordinates;\n solutionVector = newtonRaphsonResult.solutionVector;\n newtonRaphsonIterations = newtonRaphsonResult.iterations;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the solid heat transfer matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n // 2D solid heat transfer\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Create an instance of ThermalBoundaryConditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.2\";","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","debugLog","message","console","log","basicLog","errorLog","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","math","lusolve","jacobiResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiMethod","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","nodesCoordinates","totalNodes","meshConfig","meshDimension","numElementsX","numElementsY","elementOrder","parsedMesh","nodesXCoordinates","nodesX","nodesY","calculateSystemSize","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","GenericBoundaryConditions","constructor","boundaryElements","nop","this","imposeConstantValueBoundaryConditions","Object","keys","forEach","boundaryKey","value","elementIndex","side","nodeIndex","globalNodeIndex","colIndex","BasisFunctions","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","maxX","maxY","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","undefined","fixedBoundaryElements","boundaryNodePairs","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","generate1DNodalNumbering","findBoundaryElements","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","assembleFrontPropagationMat","eikonalViscousTerm","mesh","nodesCoordinatesAndNumbering","totalElements","xCoordinates","yCoordinates","ksiDerivX","etaDerivX","ksiDerivY","etaDerivY","detJacobian","solutionDerivX","solutionDerivY","localToGlobalMap","basisFunctionDerivX","basisFunctionDerivY","basisFunctions","gaussPointsAndWeights","numNodes","localNodeIndex","gaussPointIndex1","basisFunctionsAndDerivatives","gaussPointIndex2","localNodeIndex1","localToGlobalMap1","localNodeIndex2","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","Error","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","map","fromWireValue","returnValue","parent","slice","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","r","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","arr","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","thermalBoundaryConditions","assembleSolidHeatTransferMat","newtonRaphsonResult","worker","feaWorker","isReady","_initWorker","Worker","URL","document","location","require","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","result","toFixed","getModelInfo","ping","terminate","async","file","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","parseInt","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","level","plotType","plotDivId","meshType","yData","xData","from","lineData","mode","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","l","t","b","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"feascript.umd.js","sources":["../src/methods/euclideanNormScript.js","../src/utilities/loggingScript.js","../src/methods/linearSystemSolverScript.js","../src/methods/jacobiSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/utilities/helperFunctionsScript.js","../src/solvers/genericBoundaryConditionsScript.js","../src/mesh/basisFunctionsScript.js","../src/mesh/meshGenerationScript.js","../src/methods/numericalIntegrationScript.js","../src/solvers/frontPropagationScript.js","../src/solvers/thermalBoundaryConditionsScript.js","../src/vendor/comlink.mjs","../src/FEAScript.js","../src/solvers/solidHeatTransferScript.js","../src/workers/workerScript.js","../src/index.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.js"],"sourcesContent":["// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to calculate the Euclidean norm of a vector\n * @param {array} vector - The input vector\n * @returns {number} The Euclidean norm of the vector\n */\nexport function euclideanNorm(vector) {\n let norm = 0;\n for (let i = 0; i < vector.length; i++) {\n norm += vector[i] * vector[i];\n }\n norm = Math.sqrt(norm);\n return norm;\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Global logging level\nlet currentLogLevel = \"basic\";\n\n/**\n * Function to set the logging system level\n * @param {string} level - Logging level (basic, debug)\n */\nexport function logSystem(level) {\n if (level !== \"basic\" && level !== \"debug\") {\n console.log(\n \"%c[WARN] Invalid log level: \" + level + \". Using basic instead.\",\n \"color: #FFC107; font-weight: bold;\"\n ); // Yellow for warnings\n currentLogLevel = \"basic\";\n } else {\n currentLogLevel = level;\n basicLog(`Log level set to: ${level}`);\n }\n}\n\n/**\n * Function to log debug messages - only logs if level is 'debug'\n * @param {string} message - Message to log\n */\nexport function debugLog(message) {\n if (currentLogLevel === \"debug\") {\n console.log(\"%c[DEBUG] \" + message, \"color: #2196F3; font-weight: bold;\"); // Blue color for debug\n }\n}\n\n/**\n * Function to log basic information - always logs\n * @param {string} message - Message to log\n */\nexport function basicLog(message) {\n console.log(\"%c[INFO] \" + message, \"color: #4CAF50; font-weight: bold;\"); // Green color for basic info\n}\n\n/**\n * Function to log error messages\n * @param {string} message - Message to log\n */\nexport function errorLog(message) {\n console.log(\"%c[ERROR] \" + message, \"color: #F44336; font-weight: bold;\"); // Red color for errors\n}\n\n/**\n * Function to handle version information and fetch the latest update date and release from GitHub\n */\nexport async function printVersion() {\n basicLog(\"Fetching latest FEAScript version information...\");\n try {\n const commitResponse = await fetch(\"https://api.github.com/repos/FEAScript/FEAScript/commits/main\");\n const commitData = await commitResponse.json();\n const latestCommitDate = new Date(commitData.commit.committer.date).toLocaleString();\n basicLog(`Latest FEAScript update: ${latestCommitDate}`);\n return latestCommitDate;\n } catch (error) {\n errorLog(\"Failed to fetch version information: \" + error);\n return \"Version information unavailable\";\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiSolver } from \"./jacobiSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to solve a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (\"lusolve\" or \"jacobi\")\n * @param {Array} jacobianMatrix - The coefficient matrix\n * @param {Array} residualVector - The right-hand side vector\n * @param {object} [options] - Additional options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum iterations for iterative methods\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance for iterative methods\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - converged: Boolean indicating whether the method converged (for iterative methods)\n * - iterations: Number of iterations performed (for iterative methods)\n */\nexport function solveLinearSystem(solverMethod, jacobianMatrix, residualVector, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n\n let solutionVector = [];\n let converged = true;\n let iterations = 0;\n\n // Solve the linear system based on the specified solver method\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n if (solverMethod === \"lusolve\") {\n // Use LU decomposition method\n solutionVector = math.lusolve(jacobianMatrix, residualVector);\n } else if (solverMethod === \"jacobi\") {\n // Use Jacobi method\n const initialGuess = new Array(residualVector.length).fill(0);\n const jacobiSolverResult = jacobiSolver(jacobianMatrix, residualVector, initialGuess, {\n maxIterations,\n tolerance,\n });\n\n // Log convergence information\n if (jacobiSolverResult.converged) {\n debugLog(`Jacobi method converged in ${jacobiSolverResult.iterations} iterations`);\n } else {\n debugLog(`Jacobi method did not converge after ${jacobiSolverResult.iterations} iterations`);\n }\n\n solutionVector = jacobiSolverResult.solutionVector;\n converged = jacobiSolverResult.converged;\n iterations = jacobiSolverResult.iterations;\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n return { solutionVector, converged, iterations };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method\n * @param {array} jacobianMatrix - The coefficient matrix (must be square)\n * @param {array} residualVector - The right-hand side vector\n * @param {array} initialGuess - Initial guess for solution vector\n * @param {object} [options] - Options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum number of iterations\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\nexport function jacobiSolver(jacobianMatrix, residualVector, initialGuess, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n const n = jacobianMatrix.length; // Size of the square matrix\n let x = [...initialGuess]; // Current solution (starts with initial guess)\n let xNew = new Array(n); // Next iteration's solution\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n // Perform one iteration\n for (let i = 0; i < n; i++) {\n let sum = 0;\n // Calculate sum of jacobianMatrix[i][j] * x[j] for j ≠ i\n for (let j = 0; j < n; j++) {\n if (j !== i) {\n sum += jacobianMatrix[i][j] * x[j];\n }\n }\n // Update xNew[i] using the Jacobi formula\n xNew[i] = (residualVector[i] - sum) / jacobianMatrix[i][i];\n }\n\n // Check convergence\n let maxDiff = 0;\n for (let i = 0; i < n; i++) {\n maxDiff = Math.max(maxDiff, Math.abs(xNew[i] - x[i]));\n }\n\n // Update x for next iteration\n x = [...xNew];\n\n // Successfully converged if maxDiff is less than tolerance\n if (maxDiff < tolerance) {\n return {\n solutionVector: x,\n iterations: iteration + 1,\n converged: true,\n };\n }\n }\n\n // maxIterations were reached without convergence\n return {\n solutionVector: x,\n iterations: maxIterations,\n converged: false,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { euclideanNorm } from \"../methods/euclideanNormScript.js\";\nimport { solveLinearSystem } from \"./linearSystemSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\nimport { calculateSystemSize } from \"../utilities/helperFunctionsScript.js\";\n\n/**\n * Function to solve a system of nonlinear equations using the Newton-Raphson method\n * @param {number} [maxIterations=100] - Maximum number of iterations\n * @param {number} [tolerance=1e-4] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\n\nexport function newtonRaphson(assembleMat, context, maxIterations = 100, tolerance = 1e-4) {\n let errorNorm = 0;\n let converged = false;\n let iterations = 0;\n let deltaX = [];\n let solutionVector = [];\n let jacobianMatrix = [];\n let residualVector = [];\n let nodesCoordinates = {};\n\n // Calculate system size directly from meshConfig\n let totalNodes = calculateSystemSize(context.meshConfig);\n\n // Initialize arrays with proper size\n for (let i = 0; i < totalNodes; i++) {\n deltaX[i] = 0;\n solutionVector[i] = 0;\n }\n\n // Initialize solution from context if available\n if (context.initialSolution && context.initialSolution.length === totalNodes) {\n solutionVector = [...context.initialSolution];\n }\n\n while (iterations < maxIterations && !converged) {\n // Update solution\n for (let i = 0; i < solutionVector.length; i++) {\n solutionVector[i] = Number(solutionVector[i]) + Number(deltaX[i]);\n }\n\n // Compute Jacobian and residual matrices\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleMat(\n context.meshConfig,\n context.boundaryConditions,\n solutionVector, // The solution vector is required in the case of a non-linear equation\n context.eikonalActivationFlag\n ));\n\n // Solve the linear system based on the specified solver method\n const linearSystemResult = solveLinearSystem(context.solverMethod, jacobianMatrix, residualVector);\n deltaX = linearSystemResult.solutionVector;\n\n // Check convergence\n errorNorm = euclideanNorm(deltaX);\n\n // Norm for each iteration\n basicLog(`Newton-Raphson iteration ${iterations + 1}: Error norm = ${errorNorm.toExponential(4)}`);\n\n if (errorNorm <= tolerance) {\n converged = true;\n } else if (errorNorm > 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n nodesCoordinates,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Helper function to calculate system size from mesh configuration\n * @param {object} meshConfig - Mesh configuration object\n * @returns {number} Total number of nodes in the system\n */\nexport function calculateSystemSize(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, elementOrder, parsedMesh } = meshConfig;\n\n if (parsedMesh && parsedMesh.nodesXCoordinates) {\n // For parsed meshes (like from GMSH)\n return parsedMesh.nodesXCoordinates.length;\n } else {\n // For geometry-based meshes\n let nodesX,\n nodesY = 1;\n\n if (elementOrder === \"linear\") {\n nodesX = numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = numElementsY + 1;\n } else if (elementOrder === \"quadratic\") {\n nodesX = 2 * numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = 2 * numElementsY + 1;\n }\n\n return nodesX * nodesY;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n debugLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n if (\n this.numElementsX === null ||\n this.maxX === null ||\n this.numElementsY === null ||\n this.maxY === null\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n \n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\n\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the front propagation matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation (ranges from 0 to 1)\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleFrontPropagationMat(\n meshConfig,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n // TODO: The mesh generation step should be moved outside of the assembleFrontPropagationMat function so that not performed in every Newton-Raphson iteration\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n let solutionDerivX; // The x-derivative of the solution\n let solutionDerivY; // The y-derivative of the solution\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n detJacobian = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n detJacobian = ksiDerivX;\n }\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n // 2D front propagation (eikonal) equation\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n solutionDerivX = 0;\n solutionDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x & y-derivatives of basis functions and x & y-derivatives of the solution\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n // The x-derivative of the solution\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n // The y-derivative of the solution\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector - Viscous term: Add diffusion contribution to stabilize the solution\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n // residualVector - Eikonal term: Add the eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix - Viscous term: Add the Jacobian contribution from the diffusion term\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n // jacobianMatrix - Eikonal term: Add the Jacobian contribution from the eikonal equation\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n (detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)\n ) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n }\n\n // Create an instance of GenericBoundaryConditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions (Robin type)\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n let nodesCoordinates = {};\n let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term - Used in frontPropagationScript\n let newtonRaphsonIterations;\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleSolidHeatTransferMat(\n this.meshConfig,\n this.boundaryConditions\n ));\n\n // Solve the assembled linear system\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n\n // Create context object with all necessary properties\n const context = {\n meshConfig: this.meshConfig,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n nodesCoordinates = newtonRaphsonResult.nodesCoordinates;\n solutionVector = newtonRaphsonResult.solutionVector;\n newtonRaphsonIterations = newtonRaphsonResult.iterations;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the solid heat transfer matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n // 2D solid heat transfer\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Create an instance of ThermalBoundaryConditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.3\";","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","debugLog","message","console","log","basicLog","errorLog","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","math","lusolve","jacobiSolverResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiSolver","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","nodesCoordinates","totalNodes","meshConfig","meshDimension","numElementsX","numElementsY","elementOrder","parsedMesh","nodesXCoordinates","nodesX","nodesY","calculateSystemSize","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","GenericBoundaryConditions","constructor","boundaryElements","nop","this","imposeConstantValueBoundaryConditions","Object","keys","forEach","boundaryKey","value","elementIndex","side","nodeIndex","globalNodeIndex","colIndex","BasisFunctions","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","maxX","maxY","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","undefined","fixedBoundaryElements","boundaryNodePairs","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","generate1DNodalNumbering","findBoundaryElements","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","assembleFrontPropagationMat","eikonalViscousTerm","mesh","nodesCoordinatesAndNumbering","totalElements","xCoordinates","yCoordinates","ksiDerivX","etaDerivX","ksiDerivY","etaDerivY","detJacobian","solutionDerivX","solutionDerivY","localToGlobalMap","basisFunctionDerivX","basisFunctionDerivY","basisFunctions","gaussPointsAndWeights","numNodes","localNodeIndex","gaussPointIndex1","basisFunctionsAndDerivatives","gaussPointIndex2","localNodeIndex1","localToGlobalMap1","localNodeIndex2","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","Error","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","map","fromWireValue","returnValue","parent","slice","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","r","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","arr","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","thermalBoundaryConditions","assembleSolidHeatTransferMat","newtonRaphsonResult","worker","feaWorker","isReady","_initWorker","Worker","URL","document","location","require","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","result","toFixed","getModelInfo","ping","terminate","async","file","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","parseInt","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","level","plotType","plotDivId","meshType","yData","xData","from","lineData","mode","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","l","t","b","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString"],"mappings":"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"} \ No newline at end of file diff --git a/package.json b/package.json index 2539c15..8e54bf2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "feascript", - "version": "0.1.2", - "description": "A lightweight finite element simulation library built in JavaScript for browser-based physics and engineering simulations", + "version": "0.1.3", + "description": "Lightweight finite element simulation library built in JavaScript for browser-based physics and engineering simulations", "main": "dist/feascript.cjs.js", "module": "dist/feascript.esm.js", "browser": "dist/feascript.umd.js", @@ -40,6 +40,10 @@ { "name": "sridhar-mani", "url": "https://www.npmjs.com/~sridhar-mani" + }, + { + "name": "Felipe Ferrari", + "url": "https://github.com/ferrari212" } ], "license": "MIT", @@ -47,7 +51,7 @@ "bugs": { "url": "https://github.com/FEAScript/FEAScript-core/issues" }, - "homepage": "https://github.com/FEAScript/FEAScript-core#readme", + "homepage": "https://feascript.com/", "publishConfig": { "access": "public" }, diff --git a/src/FEAScript.js b/src/FEAScript.js index b7fa4d8..ec7826a 100644 --- a/src/FEAScript.js +++ b/src/FEAScript.js @@ -9,9 +9,8 @@ // Website: https://feascript.com/ \__| // // Internal imports -import { jacobiMethod } from "./methods/jacobiMethodScript.js"; import { newtonRaphson } from "./methods/newtonRaphsonScript.js"; -import { solveLinearSystem } from "./methods/linearSystemScript.js"; +import { solveLinearSystem } from "./methods/linearSystemSolverScript.js"; import { assembleFrontPropagationMat } from "./solvers/frontPropagationScript.js"; import { assembleSolidHeatTransferMat } from "./solvers/solidHeatTransferScript.js"; import { basicLog, debugLog, errorLog } from "./utilities/loggingScript.js"; diff --git a/src/index.js b/src/index.js index 12a5482..b3309b0 100644 --- a/src/index.js +++ b/src/index.js @@ -13,4 +13,4 @@ export { importGmshQuadTri } from "./readers/gmshReaderScript.js"; export { logSystem, printVersion } from "./utilities/loggingScript.js"; export { plotSolution } from "./visualization/plotSolutionScript.js"; export { FEAScriptWorker } from "./workers/workerScript.js"; -export const VERSION = "0.1.2"; \ No newline at end of file +export const VERSION = "0.1.3"; \ No newline at end of file diff --git a/src/methods/jacobiMethodScript.js b/src/methods/jacobiSolverScript.js similarity index 97% rename from src/methods/jacobiMethodScript.js rename to src/methods/jacobiSolverScript.js index bc411f3..1e85de5 100644 --- a/src/methods/jacobiMethodScript.js +++ b/src/methods/jacobiSolverScript.js @@ -21,7 +21,7 @@ * - iterations: The number of iterations performed * - converged: Boolean indicating whether the method converged */ -export function jacobiMethod(jacobianMatrix, residualVector, initialGuess, options = {}) { +export function jacobiSolver(jacobianMatrix, residualVector, initialGuess, options = {}) { const { maxIterations = 1000, tolerance = 1e-6 } = options; const n = jacobianMatrix.length; // Size of the square matrix let x = [...initialGuess]; // Current solution (starts with initial guess) diff --git a/src/methods/linearSystemScript.js b/src/methods/linearSystemSolverScript.js similarity index 82% rename from src/methods/linearSystemScript.js rename to src/methods/linearSystemSolverScript.js index 18ccc4b..0fa0bec 100644 --- a/src/methods/linearSystemScript.js +++ b/src/methods/linearSystemSolverScript.js @@ -9,7 +9,7 @@ // Website: https://feascript.com/ \__| // // Internal imports -import { jacobiMethod } from "./jacobiMethodScript.js"; +import { jacobiSolver } from "./jacobiSolverScript.js"; import { basicLog, debugLog, errorLog } from "../utilities/loggingScript.js"; /** @@ -42,21 +42,21 @@ export function solveLinearSystem(solverMethod, jacobianMatrix, residualVector, } else if (solverMethod === "jacobi") { // Use Jacobi method const initialGuess = new Array(residualVector.length).fill(0); - const jacobiResult = jacobiMethod(jacobianMatrix, residualVector, initialGuess, { + const jacobiSolverResult = jacobiSolver(jacobianMatrix, residualVector, initialGuess, { maxIterations, tolerance, }); // Log convergence information - if (jacobiResult.converged) { - debugLog(`Jacobi method converged in ${jacobiResult.iterations} iterations`); + if (jacobiSolverResult.converged) { + debugLog(`Jacobi method converged in ${jacobiSolverResult.iterations} iterations`); } else { - debugLog(`Jacobi method did not converge after ${jacobiResult.iterations} iterations`); + debugLog(`Jacobi method did not converge after ${jacobiSolverResult.iterations} iterations`); } - solutionVector = jacobiResult.solutionVector; - converged = jacobiResult.converged; - iterations = jacobiResult.iterations; + solutionVector = jacobiSolverResult.solutionVector; + converged = jacobiSolverResult.converged; + iterations = jacobiSolverResult.iterations; } else { errorLog(`Unknown solver method: ${solverMethod}`); } diff --git a/src/methods/newtonRaphsonScript.js b/src/methods/newtonRaphsonScript.js index 42ae388..869d832 100644 --- a/src/methods/newtonRaphsonScript.js +++ b/src/methods/newtonRaphsonScript.js @@ -10,7 +10,7 @@ // Internal imports import { euclideanNorm } from "../methods/euclideanNormScript.js"; -import { solveLinearSystem } from "../methods/linearSystemScript.js"; +import { solveLinearSystem } from "./linearSystemSolverScript.js"; import { basicLog, debugLog, errorLog } from "../utilities/loggingScript.js"; import { calculateSystemSize } from "../utilities/helperFunctionsScript.js"; From dbf34ce50d8ea5aed83c4807048967be12315ffc Mon Sep 17 00:00:00 2001 From: nikoscham Date: Wed, 27 Aug 2025 10:42:44 +0300 Subject: [PATCH 05/24] Enhance README and examples; add frontal solver implementation - Updated README.md to include new sections on JavaScript API and Visual Editor, improving clarity on usage methods. - Reorganized content for better navigation and added links to examples and tutorials. - Modified example scripts to improve console output order for clarity. - Introduced a new frontal solver script for 2D problems, implementing necessary mathematical functions and logic. - Created a temporary HTML file to load the frontal solver script for testing purposes. --- CONTRIBUTING.md | 155 ++-- README.md | 105 ++- .../SolidificationFront2D.js | 4 +- .../HeatConduction1DWall.js | 6 +- .../HeatConduction2DFin.js | 6 +- .../HeatConduction2DFinGmsh.js | 18 +- src/methods/frontalSolverScript.js | 703 ++++++++++++++++++ src/methods/temporaryFrontalTest.html | 1 + 8 files changed, 867 insertions(+), 131 deletions(-) create mode 100644 src/methods/frontalSolverScript.js create mode 100644 src/methods/temporaryFrontalTest.html diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ee870bd..305fe6b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,15 +4,87 @@ Thank you for your interest in contributing! FEAScript is in early development, ## Contribution Guidelines -1. **Respect the existing coding style:** Observe the code near your intended changes and aim to preserve that style in your modifications. - -2. **Recommended tools:** +1. **Development Tools:** We recommend using [Visual Studio Code](https://code.visualstudio.com/) with the [Prettier plugin](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) for automatic code formatting. Additionally, use a **110-character line width** to maintain consistent formatting. -3. **Naming conventions:** +2. **Coding Style:** + Observe the code near your intended changes and aim to preserve that style in your modifications. + +3. **Variable Naming:** Use [camelCase](https://en.wikipedia.org/wiki/Camel_case) formatting for variable names throughout the code. -4. **Testing changes locally:** +4. **File Naming:** + All JavaScript source files in FEAScript end with the suffix `Script` before the `.js` extension (e.g., `loggingScript.js`, `meshGenerationScript.js`, `newtonRaphsonScript.js`). This is an explicit, project‑level stylistic choice to: + + - Visually distinguish internal FEAScript modules from third‑party or external library files. + - Keep historical and stylistic consistency across the codebase. + + Exceptions: + + - Public entry file: `index.js` (standard entry point convention). + - Core model file: `FEAScript.js` (matches the library name; appending "Script" would be redundant). + +5. **File Structure:** + All files in the FEAScript-core codebase should follow this structure: + + 1. **Banner**: All files start with the FEAScript ASCII art banner. + 2. **Imports**: + - External imports (from npm packages) first, alphabetically ordered. + - Internal imports next, grouped by module/folder. + 3. **Classes/Functions**: Implementation with proper JSDoc comments. + + Example: + + ```javascript + // ______ ______ _____ _ _ // + // | ____| ____| /\ / ____| (_) | | // + // | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ // + // | __| | __| / /\ \ \___ \ / __| __| | _ \| __| // + // | | | |____ / ____ \ ____) | (__| | | | |_) | | // + // |_| |______/_/ \_\_____/ \___|_| |_| __/| | // + // | | | | // + // |_| | |_ // + // Website: https://feascript.com/ \__| // + + // External imports + import { mathLibrary } from "math-package"; + + // Internal imports + import { relatedFunction } from "../utilities/helperScript.js"; + + /** + * Class to handle specific functionality + */ + export class MyClass { + /** + * Constructor to initialize the class + * @param {object} options - Configuration options + */ + constructor(options) { + // Implementation + } + + /** + * Function to perform a specific action + * @param {number} input - Input value + * @returns {number} Processed result + */ + doSomething(input) { + // Implementation + return input * DEFAULT_VALUE; + } + } + ``` + +6. **Branching & Workflow:** + To contribute a new feature or fix: + + - Do not commit directly to `main` or `dev`. + - Instead, start your work in a feature branch based on the `dev` branch. + + **If you are not a member of the repository (e.g., an external contributor), you must first [fork the repository](https://docs.github.com/en/get-started/quickstart/fork-a-repo).** Make your changes in your fork, then submit a Pull Request from your fork's feature branch into the `dev` branch. + +7. **Local Testing:** Before submitting a pull request, test your modifications by running the FEAScript library from a local directory. For example, you can load the library in your HTML file as follows: ```javascript @@ -26,76 +98,3 @@ Thank you for your interest in contributing! FEAScript is in early development, ``` where the server will be available at `http://127.0.0.1:8000/`. Static file server npm packages like [serve](https://github.com/vercel/serve#readme) and [Vite](https://vite.dev/) can also be used. - -## Branching & Workflow - -To contribute a new feature or fix: - -- Do not commit directly to `main` or `dev`. -- Instead, start your work in a feature branch based on the `dev` branch. - -**If you are not a member of the repository (e.g., an external contributor), you must first [fork the repository](https://docs.github.com/en/get-started/quickstart/fork-a-repo).** Make your changes in your fork, then submit a Pull Request from your fork's feature branch into the`dev` branch. - -## File Structure Guidelines - -All files in the FEAScript-core codebase should follow this structure: - -1. **Banner**: All files start with the FEAScript ASCII art banner. -2. **Imports**: - - External imports (from npm packages) first, alphabetically ordered. - - Internal imports next, grouped by module/folder. -3. **Classes/Functions**: Implementation with proper JSDoc comments. - -Example: - -```javascript -// ______ ______ _____ _ _ // -// | ____| ____| /\ / ____| (_) | | // -// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ // -// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| // -// | | | |____ / ____ \ ____) | (__| | | | |_) | | // -// |_| |______/_/ \_\_____/ \___|_| |_| __/| | // -// | | | | // -// |_| | |_ // -// Website: https://feascript.com/ \__| // - -// External imports -import { mathLibrary } from "math-package"; - -// Internal imports -import { relatedFunction } from "../utilities/helperScript.js"; - -/** - * Class to handle specific functionality - */ -export class MyClass { - /** - * Constructor to initialize the class - * @param {object} options - Configuration options - */ - constructor(options) { - // Implementation - } - - /** - * Function to perform a specific action - * @param {number} input - Input value - * @returns {number} Processed result - */ - doSomething(input) { - // Implementation - return input * DEFAULT_VALUE; - } -} -``` - -## File Naming Convention - -All JavaScript source files in FEAScript end with the suffix `Script` before the `.js` extension (e.g., `loggingScript.js`, `meshGenerationScript.js`, `newtonRaphsonScript.js`). This is an explicit, project‑level stylistic choice to: - -- Visually distinguish internal FEAScript modules from third‑party or external library files. -- Keep historical and stylistic consistency across the codebase. - -Exceptions: -- Public entry file: `index.js` (standard entry point convention). -- Core model file: `FEAScript.js` (matches the library name; appending "Script" would be redundant). diff --git a/README.md b/README.md index 9230030..0659c69 100644 --- a/README.md +++ b/README.md @@ -2,32 +2,45 @@ # FEAScript-core -[![npm version](https://img.shields.io/npm/v/feascript)](https://www.npmjs.com/package/feascript) +[![npm version](https://img.shields.io/npm/v/feascript)](https://www.npmjs.com/package/feascript) [![liberapay](https://img.shields.io/liberapay/receives/FEAScript.svg?logo=liberapay)](https://liberapay.com/FEAScript/) [FEAScript](https://feascript.com/) is a lightweight finite element simulation library built in JavaScript. It empowers users to create and execute simulations for physics and engineering applications in both browser-based and server-side environments. This is the core library of FEAScript. > 🚧 **FEAScript is currently under heavy development.** Functionality and interfaces may change rapidly as new features and enhancements are introduced. 🚧 +## Ways to Use FEAScript + +FEAScript offers two main approaches to creating simulations: + +1. **[JavaScript API](#javascript-api)** – For developers comfortable with coding, providing full programmatic control in browsers, Node.js, or interactive notebooks. +2. **[Visual Editor (FEAScript Platform)](#visual-editor-feascript-platform)** – For users who prefer a no-code approach, offering a block-based visual interface built with [Blockly](https://developers.google.com/blockly). + +Each approach is explained in detail below. + ## Contents -- [Installation](#installation) -- [Example Usage](#example-usage) -- [FEAScript Platform](#feascript-platform) -- [Contribute](#contribute) +- [JavaScript API](#javascript-api) + - [Use FEAScript in the Browser](#use-feascript-in-the-browser) + - [Use FEAScript with Node.js](#use-feascript-with-nodejs) + - [Use FEAScript with Online Notebooks](#use-feascript-with-online-notebooks) +- [Visual Editor (FEAScript Platform)](#visual-editor-feascript-platform) +- [Quick Example](#quick-example) +- [Contributing](#contributing) - [License](#license) -## Installation +## JavaScript API -FEAScript is entirely implemented in pure JavaScript and can run in two environments: +The JavaScript API is the core programmatic interface for FEAScript. Written entirely in pure JavaScript, it runs in three environments: -1. **In the browser** with a simple HTML page, where all simulations are executed locally without any installations or using any cloud services. -2. **Via Node.js** with plain JavaScript files, for server-side simulations. +1. **[In the browser](#use-feascript-in-the-browser)** – Use FEAScript in a simple HTML page where simulations run locally without installations or cloud services. +2. **[With Node.js](#use-feascript-with-nodejs)** – Use FEAScript in server-side JavaScript applications or CLI tools. +3. **[With Online Notebooks](#use-feascript-with-online-notebooks)** – Try FEAScript in interactive JavaScript notebook environments with built-in visualization, such as [Scribbler](https://scribbler.live/). -### Option 1: In the Browser +### Use FEAScript in the Browser You can use FEAScript in browser environments in two ways: -**Direct Import from the Web (ES Module):** +**Import from Hosted ESM Build:** ```html ``` -You can download the latest stable release from [GitHub Releases](https://github.com/FEAScript/FEAScript-core/releases). Explore various browser-based examples and use cases in our [website](https://feascript.com/#tutorials). +👉 Explore various browser-based examples and use cases on our [website](https://feascript.com/#tutorials). -### Option 2: Via Node.js +### Use FEAScript with Node.js Install FEAScript and its peer dependencies from npm: @@ -66,11 +81,29 @@ import { FEAScriptModel } from "feascript"; echo '{"type":"module"}' > package.json ``` -When running examples from within this repository, this step is not needed as the root package.json already has the proper configuration. Explore various Node.js examples and use cases [here](https://github.com/FEAScript/FEAScript-core/tree/main/examples). +When running examples from within this repository, this step is not needed as the root package.json already has the proper configuration. + +👉 Explore various Node.js examples and use cases [here](https://github.com/FEAScript/FEAScript-core/tree/main/examples). + +### Use FEAScript with Online Notebooks -## Example Usage +FEAScript works well in interactive JavaScript notebook environments, where you can write code, visualize results inline, and share your work with others. [Scribbler](https://scribbler.live/) is one such platform that comes with preloaded scientific libraries, making it an excellent choice for FEAScript simulations. -This is an indicative example of FEAScript, shown for execution in the browser. Adapt paths, solver types, and boundary conditions as needed for your specific problem: +👉 Explore various FEAScript examples on [Scribbler Hub](https://hub.scribbler.live/portfolio/#!nikoscham/FEAScript-Scribbler-examples). + +## Visual Editor (FEAScript Platform) + +For users who prefer a visual approach to creating simulations, we offer the [FEAScript platform](https://platform.feascript.com/) - a browser-based visual editor built on the [Blockly](https://developers.google.com/blockly) library. This no-code interface allows you to: + +- Build and run finite element simulations directly in your browser by connecting visual blocks +- Create complex simulations without writing any JavaScript code +- Save and load projects in XML format for easy sharing and reuse + +While FEAScript's JavaScript API offers full programmatic control for advanced customization, the FEAScript platform provides an accessible entry point for users without coding experience. + +## Quick Example + +Here is a minimal browser-based example using the JavaScript API. Adapt paths, solver types, and boundary conditions as needed for your specific problem: ```html @@ -80,22 +113,26 @@ This is an indicative example of FEAScript, shown for execution in the browser. import { FEAScriptModel } from "https://core.feascript.com/dist/feascript.esm.js"; window.addEventListener("DOMContentLoaded", async () => { - // Create and configure model + // Create a new FEAScript model const model = new FEAScriptModel(); - model.setSolverConfig("solverType"); // e.g., "solidHeatTransfer" for a stationary solid heat transfer case + + // Set the solver type for your problem + model.setSolverConfig("solverType"); // Example: "solidHeatTransferScript" + + // Configure the mesh model.setMeshConfig({ - meshDimension: "1D" | "2D", // Mesh dimension - elementOrder: "linear" | "quadratic", // Element order - numElementsX: number, // Number of elements in x-direction - numElementsY: number, // Number of elements in y-direction (for 2D) - maxX: number, // Domain length in x-direction - maxY: number, // Domain length in y-direction (for 2D) + meshDimension: "1D", // Choose either: "1D" or "2D" + elementOrder: "linear", // Choose either: "linear" or "quadratic" + numElementsX: 10, // Number of elements in x-direction + numElementsY: 6, // Number of elements in y-direction (for 2D only) + maxX: 1.0, // Domain length in x-direction + maxY: 0.5, // Domain length in y-direction (for 2D only) }); - // Apply boundary conditions - model.addBoundaryCondition("boundaryIndex", ["conditionType" /* parameters */]); + // Add boundary conditions with appropriate parameters + model.addBoundaryCondition("boundaryIndex", ["conditionType" /* parameters */]); // Example boundary condition - // Solve + // Solve the problem const { solutionVector, nodesCoordinates } = model.solve(); }); @@ -103,17 +140,13 @@ This is an indicative example of FEAScript, shown for execution in the browser. ``` -## FEAScript Platform +**Note:** The code above uses placeholder values that you should replace with appropriate options, e.g.: -For users who prefer a visual approach to creating simulations, we offer the [FEAScript platform](https://platform.feascript.com/) - a browser-based visual editor built on the [Blockly](https://developers.google.com/blockly) library. This no-code interface allows you to: - -- Build and run finite element simulations directly in your browser by connecting visual blocks -- Create complex simulations without writing any JavaScript code -- Save and load projects in XML format for easy sharing and reuse - -While FEAScript's JavaScript API offers full programmatic control for advanced customization, the FEAScript platform provides an accessible entry point for users without coding experience. +- "solverType" should be replaced with an actual solver type such as "solidHeatTransferScript" for heat conduction problems +- "conditionType" should be replaced with an actual boundary condition type such as "constantTemp" +- "boundaryIndex" should be replaced with a string identifying the boundary -## Contribute +## Contributing We warmly welcome contributors to help expand and refine FEAScript. Please see the [CONTRIBUTING.md](./CONTRIBUTING.md) file for detailed guidance on how to contribute. diff --git a/examples/frontPropagationScript/SolidificationFront2D/SolidificationFront2D.js b/examples/frontPropagationScript/SolidificationFront2D/SolidificationFront2D.js index 3a4513e..3991d1d 100644 --- a/examples/frontPropagationScript/SolidificationFront2D/SolidificationFront2D.js +++ b/examples/frontPropagationScript/SolidificationFront2D/SolidificationFront2D.js @@ -46,6 +46,6 @@ model.setSolverMethod("lusolve"); const { solutionVector, nodesCoordinates } = model.solve(); // Print results to console -console.log("Solution vector:", solutionVector); -console.log("Node coordinates:", nodesCoordinates); console.log(`Number of nodes in mesh: ${nodesCoordinates.nodesXCoordinates.length}`); +console.log("Node coordinates:", nodesCoordinates); +console.log("Solution vector:", solutionVector); diff --git a/examples/solidHeatTransferScript/HeatConduction1DWall/HeatConduction1DWall.js b/examples/solidHeatTransferScript/HeatConduction1DWall/HeatConduction1DWall.js index f637453..1944d5c 100644 --- a/examples/solidHeatTransferScript/HeatConduction1DWall/HeatConduction1DWall.js +++ b/examples/solidHeatTransferScript/HeatConduction1DWall/HeatConduction1DWall.js @@ -15,7 +15,7 @@ global.math = math; // Import FEAScript library import { FEAScriptModel, logSystem, VERSION } from "feascript"; -console.log('FEAScript Version:', VERSION); +console.log("FEAScript Version:", VERSION); // Create a new FEAScript model const model = new FEAScriptModel(); @@ -42,6 +42,6 @@ model.setSolverMethod("lusolve"); const { solutionVector, nodesCoordinates } = model.solve(); // Print results to console -console.log("Solution vector:", solutionVector); -console.log("Node coordinates:", nodesCoordinates); console.log(`Number of nodes: ${nodesCoordinates.nodesXCoordinates.length}`); +console.log("Node coordinates:", nodesCoordinates); +console.log("Solution vector:", solutionVector); diff --git a/examples/solidHeatTransferScript/HeatConduction2DFin/HeatConduction2DFin.js b/examples/solidHeatTransferScript/HeatConduction2DFin/HeatConduction2DFin.js index 76de95f..81b430b 100644 --- a/examples/solidHeatTransferScript/HeatConduction2DFin/HeatConduction2DFin.js +++ b/examples/solidHeatTransferScript/HeatConduction2DFin/HeatConduction2DFin.js @@ -15,7 +15,7 @@ global.math = math; // Import FEAScript library import { FEAScriptModel, logSystem, VERSION } from "feascript"; -console.log('FEAScript Version:', VERSION); +console.log("FEAScript Version:", VERSION); // Create a new FEAScript model const model = new FEAScriptModel(); @@ -46,6 +46,6 @@ model.setSolverMethod("lusolve"); const { solutionVector, nodesCoordinates } = model.solve(); // Print results to console -console.log("Solution vector:", solutionVector); -console.log("Node coordinates:", nodesCoordinates); console.log(`Number of nodes in mesh: ${nodesCoordinates.nodesXCoordinates.length}`); +console.log("Node coordinates:", nodesCoordinates); +console.log("Solution vector:", solutionVector); diff --git a/examples/solidHeatTransferScript/HeatConduction2DFin/HeatConduction2DFinGmsh.js b/examples/solidHeatTransferScript/HeatConduction2DFin/HeatConduction2DFinGmsh.js index b992c02..367ebb4 100644 --- a/examples/solidHeatTransferScript/HeatConduction2DFin/HeatConduction2DFinGmsh.js +++ b/examples/solidHeatTransferScript/HeatConduction2DFin/HeatConduction2DFinGmsh.js @@ -9,9 +9,9 @@ // Website: https://feascript.com/ \__| // // Import required Node.js modules -import fs from 'fs'; -import path from 'path'; -import { fileURLToPath } from 'url'; +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; // Import Math.js import * as math from "mathjs"; @@ -20,14 +20,14 @@ global.math = math; // Import FEAScript library import { FEAScriptModel, importGmshQuadTri, logSystem, VERSION } from "feascript"; -console.log('FEAScript Version:', VERSION); +console.log("FEAScript Version:", VERSION); // Get directory name for the current file const __dirname = path.dirname(fileURLToPath(import.meta.url)); // Read the mesh file -const meshFilePath = path.join(__dirname, 'rect_quad_unstruct.msh'); -const meshContent = fs.readFileSync(meshFilePath, 'utf8'); +const meshFilePath = path.join(__dirname, "rect_quad_unstruct.msh"); +const meshContent = fs.readFileSync(meshFilePath, "utf8"); async function main() { // Create a new FEAScript model @@ -39,7 +39,7 @@ async function main() { // Create a mock File object for Node.js environment const mockFile = { text: async () => meshContent, - name: 'rect_quad_unstruct.msh' + name: "rect_quad_unstruct.msh", }; // Parse the mesh data @@ -62,9 +62,9 @@ async function main() { const { solutionVector, nodesCoordinates } = model.solve(); // Print results to console - console.log("Solution vector:", solutionVector); - console.log("Node coordinates:", nodesCoordinates); console.log(`Number of nodes in mesh: ${nodesCoordinates.nodesXCoordinates.length}`); + console.log("Node coordinates:", nodesCoordinates); + console.log("Solution vector:", solutionVector); } // Run the main function diff --git a/src/methods/frontalSolverScript.js b/src/methods/frontalSolverScript.js new file mode 100644 index 0000000..fab5ae7 --- /dev/null +++ b/src/methods/frontalSolverScript.js @@ -0,0 +1,703 @@ +// Constants +const nemax = 1600; +const nnmax = 6724; +const nmax = 2000; + +// Common block equivalents as objects +const block1 = { + nex: 0, + ney: 0, + nnx: 0, + nny: 0, + ne: 0, + np: 0, + xorigin: 0, + yorigin: 0, + xlast: 0, + ylast: 0, + deltax: 0, + deltay: 0, + nop: Array(nemax) + .fill() + .map(() => Array(9).fill(0)), + xpt: Array(nnmax).fill(0), + ypt: Array(nnmax).fill(0), + ncod: Array(nnmax).fill(0), + bc: Array(nnmax).fill(0), + r1: Array(nnmax).fill(0), + u: Array(nnmax).fill(0), + ntop: Array(nemax).fill(0), + nlat: Array(nemax).fill(0), +}; + +const gauss = { + w: [0.27777777777778, 0.444444444444, 0.27777777777778], + gp: [0.1127016654, 0.5, 0.8872983346], +}; + +const fro1 = { + iwr1: 0, + npt: 0, + ntra: 0, + nbn: Array(nemax).fill(0), + det: 1, + sk: Array(nmax * nmax).fill(0), + ice1: 0, +}; + +const fabf1 = { + estifm: Array(9) + .fill() + .map(() => Array(9).fill(0)), + nell: 0, +}; + +const fb1 = { + ecv: Array(2000000).fill(0), + lhed: Array(nmax).fill(0), + qq: Array(nmax).fill(0), + ecpiv: Array(2000000).fill(0), +}; + +// Main program logic +function main() { + console.log("2-D problem. Biquadratic basis functions\n"); + xydiscr(); + nodnumb(); + xycoord(); + console.log(`nex=${block1.nex} ney=${block1.ney} ne=${block1.ne} np=${block1.np}\n`); + + // Prepare essential boundary conditions + for (let i = 0; i < block1.np; i++) { + block1.ncod[i] = 0; + block1.bc[i] = 0; + } + + for (let i = 0; i < block1.nny; i++) { + block1.ncod[i] = 1; + block1.bc[i] = 0; + } + + for (let i = 0; i < block1.np; i += block1.nny) { + block1.ncod[i] = 1; + block1.bc[i] = 0; + } + + // Prepare natural boundary conditions + for (let i = 0; i < block1.ne; i++) { + block1.ntop[i] = 0; + block1.nlat[i] = 0; + } + + for (let i = block1.ney - 1; i < block1.ne; i += block1.ney) { + block1.ntop[i] = 1; + } + + for (let i = block1.ne - block1.ney; i < block1.ne; i++) { + block1.nlat[i] = 1; + } + + // Initialization + for (let i = 0; i < block1.np; i++) { + block1.r1[i] = 0; + } + + fro1.npt = block1.np; + fro1.iwr1 = 0; + fro1.ntra = 1; + fro1.det = 1; + + for (let i = 0; i < block1.ne; i++) { + fro1.nbn[i] = 9; + } + + front(); + + // Copy solution + for (let i = 0; i < block1.np; i++) { + block1.u[i] = fro1.sk[i]; + } + + // Output results to console + for (let i = 0; i < block1.np; i++) { + console.log( + `${block1.xpt[i].toExponential(5)} ${block1.ypt[i].toExponential(5)} ${block1.u[i].toExponential(5)}` + ); + } +} + +// Discretization +function xydiscr() { + block1.nex = 12; + block1.ney = 8; + block1.xorigin = 0; + block1.yorigin = 0; + block1.xlast = 1; + block1.ylast = 1; + block1.deltax = (block1.xlast - block1.xorigin) / block1.nex; + block1.deltay = (block1.ylast - block1.yorigin) / block1.ney; +} + +// Nodal numbering +function nodnumb() { + block1.ne = block1.nex * block1.ney; + block1.nnx = 2 * block1.nex + 1; + block1.nny = 2 * block1.ney + 1; + block1.np = block1.nnx * block1.nny; + + let nel = 0; + for (let i = 1; i <= block1.nex; i++) { + for (let j = 1; j <= block1.ney; j++) { + nel++; + for (let k = 1; k <= 3; k++) { + let l = 3 * k - 2; + block1.nop[nel - 1][l - 1] = block1.nny * (2 * i + k - 3) + 2 * j - 1; + block1.nop[nel - 1][l] = block1.nop[nel - 1][l - 1] + 1; + block1.nop[nel - 1][l + 1] = block1.nop[nel - 1][l - 1] + 2; + } + } + } +} + +// Coordinate setup +function xycoord() { + block1.xpt[0] = block1.xorigin; + block1.ypt[0] = block1.yorigin; + + for (let i = 1; i <= block1.nnx; i++) { + let nnode = (i - 1) * block1.nny; + block1.xpt[nnode] = block1.xpt[0] + ((i - 1) * block1.deltax) / 2; + block1.ypt[nnode] = block1.ypt[0]; + + for (let j = 2; j <= block1.nny; j++) { + block1.xpt[nnode + j - 1] = block1.xpt[nnode]; + block1.ypt[nnode + j - 1] = block1.ypt[nnode] + ((j - 1) * block1.deltay) / 2; + } + } +} + +// Basis functions +function tsfun(x, y) { + const tsfn = { + phi: Array(9).fill(0), + phic: Array(9).fill(0), + phie: Array(9).fill(0), + }; + + const l1 = (c) => 2 * c * c - 3 * c + 1; + const l2 = (c) => -4 * c * c + 4 * c; + const l3 = (c) => 2 * c * c - c; + const dl1 = (c) => 4 * c - 3; + const dl2 = (c) => -8 * c + 4; + const dl3 = (c) => 4 * c - 1; + + tsfn.phi[0] = l1(x) * l1(y); + tsfn.phi[1] = l1(x) * l2(y); + tsfn.phi[2] = l1(x) * l3(y); + tsfn.phi[3] = l2(x) * l1(y); + tsfn.phi[4] = l2(x) * l2(y); + tsfn.phi[5] = l2(x) * l3(y); + tsfn.phi[6] = l3(x) * l1(y); + tsfn.phi[7] = l3(x) * l2(y); + tsfn.phi[8] = l3(x) * l3(y); + + tsfn.phic[0] = l1(y) * dl1(x); + tsfn.phic[1] = l2(y) * dl1(x); + tsfn.phic[2] = l3(y) * dl1(x); + tsfn.phic[3] = l1(y) * dl2(x); + tsfn.phic[4] = l2(y) * dl2(x); + tsfn.phic[5] = l3(y) * dl2(x); + tsfn.phic[6] = l1(y) * dl3(x); + tsfn.phic[7] = l2(y) * dl3(x); + tsfn.phic[8] = l3(y) * dl3(x); + + tsfn.phie[0] = l1(x) * dl1(y); + tsfn.phie[1] = l1(x) * dl2(y); + tsfn.phie[2] = l1(x) * dl3(y); + tsfn.phie[3] = l2(x) * dl1(y); + tsfn.phie[4] = l2(x) * dl2(y); + tsfn.phie[5] = l2(x) * dl3(y); + tsfn.phie[6] = l3(x) * dl1(y); + tsfn.phie[7] = l3(x) * dl2(y); + tsfn.phie[8] = l3(x) * dl3(y); + + return tsfn; +} + +// Element stiffness matrix and residuals +function abfind() { + let ngl = Array(9).fill(0); + let tphx = Array(9).fill(0); + let tphy = Array(9).fill(0); + + // Initialize stiffness matrix + for (let i = 0; i < 9; i++) { + for (let j = 0; j < 9; j++) { + fabf1.estifm[i][j] = 0; + } + } + + for (let i = 0; i < 9; i++) { + ngl[i] = Math.abs(block1.nop[fabf1.nell - 1][i]); + } + + for (let j = 0; j < 3; j++) { + for (let k = 0; k < 3; k++) { + let ts = tsfun(gauss.gp[j], gauss.gp[k]); + let x1 = 0, + x2 = 0, + y1 = 0, + y2 = 0; + + for (let n = 0; n < 9; n++) { + x1 += block1.xpt[ngl[n] - 1] * ts.phic[n]; + x2 += block1.xpt[ngl[n] - 1] * ts.phie[n]; + y1 += block1.ypt[ngl[n] - 1] * ts.phic[n]; + y2 += block1.ypt[ngl[n] - 1] * ts.phie[n]; + } + + let dett = x1 * y2 - x2 * y1; + + for (let i = 0; i < 9; i++) { + tphx[i] = (y2 * ts.phic[i] - y1 * ts.phie[i]) / dett; + tphy[i] = (x1 * ts.phie[i] - x2 * ts.phic[i]) / dett; + } + + for (let l = 0; l < 9; l++) { + for (let m = 0; m < 9; m++) { + fabf1.estifm[l][m] -= gauss.w[j] * gauss.w[k] * dett * (tphx[l] * tphx[m] + tphy[l] * tphy[m]); + } + } + } + } + + if (block1.ntop[fabf1.nell - 1] !== 1 && block1.nlat[fabf1.nell - 1] !== 1) return; + + if (block1.ntop[fabf1.nell - 1] === 1) { + for (let k1 = 0; k1 < 3; k1++) { + let ts = tsfun(gauss.gp[k1], 1); + let x = 0, + x1 = 0; + + for (let n = 0; n < 9; n++) { + x += block1.xpt[ngl[n] - 1] * ts.phi[n]; + x1 += block1.xpt[ngl[n] - 1] * ts.phic[n]; + } + + for (let k11 of [2, 5, 8]) { + block1.r1[ngl[k11] - 1] -= gauss.w[k1] * x1 * ts.phi[k11] * x; + } + } + } + + if (block1.nlat[fabf1.nell - 1] === 1) { + for (let k2 = 0; k2 < 3; k2++) { + let ts = tsfun(1, gauss.gp[k2]); + let y = 0, + y2 = 0; + + for (let n = 0; n < 9; n++) { + y += block1.ypt[ngl[n] - 1] * ts.phi[n]; + y2 += block1.ypt[ngl[n] - 1] * ts.phie[n]; + } + + for (let k21 of [6, 7, 8]) { + block1.r1[ngl[k21] - 1] -= gauss.w[k2] * y2 * ts.phi[k21] * y; + } + } + } +} + +// Frontal solver +function front() { + let ldest = Array(9).fill(0); + let kdest = Array(9).fill(0); + let khed = Array(nmax).fill(0); + let kpiv = Array(nmax).fill(0); + let lpiv = Array(nmax).fill(0); + let jmod = Array(nmax).fill(0); + let pvkol = Array(nmax).fill(0); + let eq = Array(nmax) + .fill() + .map(() => Array(nmax).fill(0)); + let nrs = Array(nnmax).fill(0); + let ncs = Array(nnmax).fill(0); + let check = Array(nnmax).fill(0); + let lco; // Declare lco once at function scope + + let ice = 1; + fro1.iwr1++; + let ipiv = 1; + let nsum = 1; + fabf1.nell = 0; + + for (let i = 0; i < fro1.npt; i++) { + nrs[i] = 0; + ncs[i] = 0; + } + + if (fro1.ntra !== 0) { + // Prefront: find last appearance of each node + for (let i = 0; i < fro1.npt; i++) { + check[i] = 0; + } + + for (let i = 0; i < block1.ne; i++) { + let nep = block1.ne - i - 1; + for (let j = 0; j < fro1.nbn[nep]; j++) { + let k = block1.nop[nep][j]; + if (check[k - 1] === 0) { + check[k - 1] = 1; + block1.nop[nep][j] = -block1.nop[nep][j]; + } + } + } + } + + fro1.ntra = 0; + let lcol = 0; + let krow = 0; + + for (let i = 0; i < nmax; i++) { + for (let j = 0; j < nmax; j++) { + eq[j][i] = 0; + } + } + + while (true) { + fabf1.nell++; + abfind(); + + let n = fabf1.nell; + let nend = fro1.nbn[n - 1]; + let lend = fro1.nbn[n - 1]; + + for (let lk = 0; lk < lend; lk++) { + let nodk = block1.nop[n - 1][lk]; + let ll; + + if (lcol === 0) { + lcol++; + ldest[lk] = lcol; + fb1.lhed[lcol - 1] = nodk; + } else { + for (ll = 0; ll < lcol; ll++) { + if (Math.abs(nodk) === Math.abs(fb1.lhed[ll])) break; + } + + if (ll === lcol) { + lcol++; + ldest[lk] = lcol; + fb1.lhed[lcol - 1] = nodk; + } else { + ldest[lk] = ll + 1; + fb1.lhed[ll] = nodk; + } + } + + let kk; + if (krow === 0) { + krow++; + kdest[lk] = krow; + khed[krow - 1] = nodk; + } else { + for (kk = 0; kk < krow; kk++) { + if (Math.abs(nodk) === Math.abs(khed[kk])) break; + } + + if (kk === krow) { + krow++; + kdest[lk] = krow; + khed[krow - 1] = nodk; + } else { + kdest[lk] = kk + 1; + khed[kk] = nodk; + } + } + } + + if (krow > nmax || lcol > nmax) { + console.error("Error: nmax-nsum not large enough"); + return; + } + + for (let l = 0; l < lend; l++) { + let ll = ldest[l]; + for (let k = 0; k < nend; k++) { + let kk = kdest[k]; + eq[kk - 1][ll - 1] += fabf1.estifm[k][l]; + } + } + + let lc = 0; + for (let l = 0; l < lcol; l++) { + if (fb1.lhed[l] < 0) { + lpiv[lc] = l + 1; + lc++; + } + } + + let ir = 0; + let kr = 0; + for (let k = 0; k < krow; k++) { + let kt = khed[k]; + if (kt < 0) { + kpiv[kr] = k + 1; + kr++; + let kro = Math.abs(kt); + if (block1.ncod[kro - 1] === 1) { + jmod[ir] = k + 1; + ir++; + block1.ncod[kro - 1] = 2; + block1.r1[kro - 1] = block1.bc[kro - 1]; + } + } + } + + if (ir > 0) { + for (let irr = 0; irr < ir; irr++) { + let k = jmod[irr] - 1; + let kh = Math.abs(khed[k]); + for (let l = 0; l < lcol; l++) { + eq[k][l] = 0; + let lh = Math.abs(fb1.lhed[l]); + if (lh === kh) eq[k][l] = 1; + } + } + } + + if (lc > nsum || fabf1.nell < block1.ne) { + if (lc === 0) { + console.error("Error: no more rows fully summed"); + return; + } + + let kpivro = kpiv[0]; + let lpivco = lpiv[0]; + let pivot = eq[kpivro - 1][lpivco - 1]; + + if (Math.abs(pivot) < 1e-4) { + pivot = 0; + for (let l = 0; l < lc; l++) { + let lpivc = lpiv[l]; + for (let k = 0; k < kr; k++) { + let kpivr = kpiv[k]; + let piva = eq[kpivr - 1][lpivc - 1]; + if (Math.abs(piva) > Math.abs(pivot)) { + pivot = piva; + lpivco = lpivc; + kpivro = kpivr; + } + } + } + } + + let kro = Math.abs(khed[kpivro - 1]); + lco = Math.abs(fb1.lhed[lpivco - 1]); // Assign, don't declare + let nhlp = kro + lco + nrs[kro - 1] + ncs[lco - 1]; + fro1.det = (fro1.det * pivot * (-1) ** nhlp) / Math.abs(pivot); + + for (let iperm = 0; iperm < fro1.npt; iperm++) { + if (iperm >= kro) nrs[iperm]--; + if (iperm >= lco) ncs[iperm]--; + } + + if (Math.abs(pivot) < 1e-10) { + console.warn( + `Warning: matrix singular or ill-conditioned, nell=${fabf1.nell}, kro=${kro}, lco=${lco}, pivot=${pivot}` + ); + } + + if (pivot === 0) return; + + for (let l = 0; l < lcol; l++) { + fb1.qq[l] = eq[kpivro - 1][l] / pivot; + } + + let rhs = block1.r1[kro - 1] / pivot; + block1.r1[kro - 1] = rhs; + pvkol[kpivro - 1] = pivot; + + if (kpivro > 1) { + for (let k = 0; k < kpivro - 1; k++) { + let krw = Math.abs(khed[k]); + let fac = eq[k][lpivco - 1]; + pvkol[k] = fac; + if (lpivco > 1 && fac !== 0) { + for (let l = 0; l < lpivco - 1; l++) { + eq[k][l] -= fac * fb1.qq[l]; + } + } + if (lpivco < lcol) { + for (let l = lpivco; l < lcol; l++) { + eq[k][l - 1] = eq[k][l] - fac * fb1.qq[l]; + } + } + block1.r1[krw - 1] -= fac * rhs; + } + } + + if (kpivro < krow) { + for (let k = kpivro; k < krow; k++) { + let krw = Math.abs(khed[k]); + let fac = eq[k][lpivco - 1]; + pvkol[k] = fac; + if (lpivco > 1) { + for (let l = 0; l < lpivco - 1; l++) { + eq[k - 1][l] = eq[k][l] - fac * fb1.qq[l]; + } + } + if (lpivco < lcol) { + for (let l = lpivco; l < lcol; l++) { + eq[k - 1][l - 1] = eq[k][l] - fac * fb1.qq[l]; + } + } + block1.r1[krw - 1] -= fac * rhs; + } + } + + for (let i = 0; i < krow; i++) { + fb1.ecpiv[ipiv + i - 1] = pvkol[i]; + } + ipiv += krow; + + for (let i = 0; i < krow; i++) { + fb1.ecpiv[ipiv + i - 1] = khed[i]; + } + ipiv += krow; + + fb1.ecpiv[ipiv - 1] = kpivro; + ipiv++; + + for (let i = 0; i < lcol; i++) { + fb1.ecv[ice - 1 + i] = fb1.qq[i]; + } + ice += lcol; + + for (let i = 0; i < lcol; i++) { + fb1.ecv[ice - 1 + i] = fb1.lhed[i]; + } + ice += lcol; + + fb1.ecv[ice - 1] = kro; + fb1.ecv[ice] = lcol; + fb1.ecv[ice + 1] = lpivco; + fb1.ecv[ice + 2] = pivot; + ice += 4; + + for (let k = 0; k < krow; k++) { + eq[k][lcol - 1] = 0; + } + + for (let l = 0; l < lcol; l++) { + eq[krow - 1][l] = 0; + } + + lcol--; + if (lpivco < lcol + 1) { + for (let l = lpivco - 1; l < lcol; l++) { + fb1.lhed[l] = fb1.lhed[l + 1]; + } + } + + krow--; + if (kpivro < krow + 1) { + for (let k = kpivro - 1; k < krow; k++) { + khed[k] = khed[k + 1]; + } + } + + if (krow > 1 || fabf1.nell < block1.ne) continue; + + lco = Math.abs(fb1.lhed[0]); // Assign, don't declare + kpivro = 1; + pivot = eq[0][0]; + kro = Math.abs(khed[0]); + lpivco = 1; + nhlp = kro + lco + nrs[kro - 1] + ncs[lco - 1]; + fro1.det = (fro1.det * pivot * (-1) ** nhlp) / Math.abs(pivot); + + fb1.qq[0] = 1; + if (Math.abs(pivot) < 1e-10) { + console.warn( + `Warning: matrix singular or ill-conditioned, nell=${fabf1.nell}, kro=${kro}, lco=${lco}, pivot=${pivot}` + ); + } + + if (pivot === 0) return; + + block1.r1[kro - 1] = block1.r1[kro - 1] / pivot; + fb1.ecv[ice - 1] = fb1.qq[0]; + ice++; + fb1.ecv[ice - 1] = fb1.lhed[0]; + ice++; + fb1.ecv[ice - 1] = kro; + fb1.ecv[ice] = lcol; + fb1.ecv[ice + 1] = lpivco; + fb1.ecv[ice + 2] = pivot; + ice += 4; + + fb1.ecpiv[ipiv - 1] = pvkol[0]; + ipiv++; + fb1.ecpiv[ipiv - 1] = khed[0]; + ipiv++; + fb1.ecpiv[ipiv - 1] = kpivro; + ipiv++; + + fro1.ice1 = ice; + if (fro1.iwr1 === 1) console.log(`total ecs transfer in matrix reduction=${ice}`); + + bacsub(ice); + break; + } + } +} + +// Back substitution +function bacsub(ice) { + for (let i = 0; i < fro1.npt; i++) { + fro1.sk[i] = block1.bc[i]; + } + + for (let iv = 1; iv <= fro1.npt; iv++) { + ice -= 4; + let kro = fb1.ecv[ice - 1]; + let lcol = fb1.ecv[ice]; + let lpivco = fb1.ecv[ice + 1]; + let pivot = fb1.ecv[ice + 2]; + + if (iv === 1) { + ice--; + fb1.lhed[0] = fb1.ecv[ice - 1]; + ice--; + fb1.qq[0] = fb1.ecv[ice - 1]; + } else { + ice -= lcol; + for (let iii = 0; iii < lcol; iii++) { + fb1.lhed[iii] = fb1.ecv[ice - 1 + iii]; + } + ice -= lcol; + for (let iii = 0; iii < lcol; iii++) { + fb1.qq[iii] = fb1.ecv[ice - 1 + iii]; + } + } + + let lco = Math.abs(fb1.lhed[lpivco - 1]); + if (block1.ncod[lco - 1] > 0) continue; + + let gash = 0; + fb1.qq[lpivco - 1] = 0; + for (let l = 0; l < lcol; l++) { + gash -= fb1.qq[l] * fro1.sk[Math.abs(fb1.lhed[l]) - 1]; + } + + fro1.sk[lco - 1] = gash + block1.r1[kro - 1]; + + block1.ncod[lco - 1] = 1; + } + + if (fro1.iwr1 === 1) console.log(`value of ice after backsubstitution=${ice}`); +} + +// Run the program +main(); diff --git a/src/methods/temporaryFrontalTest.html b/src/methods/temporaryFrontalTest.html new file mode 100644 index 0000000..f6b378a --- /dev/null +++ b/src/methods/temporaryFrontalTest.html @@ -0,0 +1 @@ + \ No newline at end of file From 6fa776912c9278137531d950347dec41b60253d2 Mon Sep 17 00:00:00 2001 From: nikoscham Date: Wed, 27 Aug 2025 10:49:13 +0300 Subject: [PATCH 06/24] Reorganize README structure; move "Ways to Use FEAScript" section for better clarity --- README.md | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 0659c69..471e7ca 100644 --- a/README.md +++ b/README.md @@ -8,17 +8,9 @@ > 🚧 **FEAScript is currently under heavy development.** Functionality and interfaces may change rapidly as new features and enhancements are introduced. 🚧 -## Ways to Use FEAScript - -FEAScript offers two main approaches to creating simulations: - -1. **[JavaScript API](#javascript-api)** – For developers comfortable with coding, providing full programmatic control in browsers, Node.js, or interactive notebooks. -2. **[Visual Editor (FEAScript Platform)](#visual-editor-feascript-platform)** – For users who prefer a no-code approach, offering a block-based visual interface built with [Blockly](https://developers.google.com/blockly). - -Each approach is explained in detail below. - ## Contents +- [Ways to Use FEAScript](#ways-to-use-feascript) - [JavaScript API](#javascript-api) - [Use FEAScript in the Browser](#use-feascript-in-the-browser) - [Use FEAScript with Node.js](#use-feascript-with-nodejs) @@ -28,6 +20,15 @@ Each approach is explained in detail below. - [Contributing](#contributing) - [License](#license) +## Ways to Use FEAScript + +FEAScript offers two main approaches to creating simulations: + +1. **[JavaScript API](#javascript-api)** – For developers comfortable with coding, providing full programmatic control in browsers, Node.js, or interactive notebooks. +2. **[Visual Editor (FEAScript Platform)](#visual-editor-feascript-platform)** – For users who prefer a no-code approach, offering a block-based visual interface built with [Blockly](https://developers.google.com/blockly). + +Each approach is explained in detail below. + ## JavaScript API The JavaScript API is the core programmatic interface for FEAScript. Written entirely in pure JavaScript, it runs in three environments: @@ -40,23 +41,23 @@ The JavaScript API is the core programmatic interface for FEAScript. Written ent You can use FEAScript in browser environments in two ways: -**Import from Hosted ESM Build:** +- **Import from Hosted ESM Build:** -```html - -``` + ```html + + ``` -**Download and Use Locally:** +- **Download and Use Locally:** -You can download the latest stable release from [GitHub Releases](https://github.com/FEAScript/FEAScript-core/releases). + You can download the latest stable release from [GitHub Releases](https://github.com/FEAScript/FEAScript-core/releases). -```html - -``` + ```html + + ``` 👉 Explore various browser-based examples and use cases on our [website](https://feascript.com/#tutorials). From bcf2492348ccd27380b0016bcea371cfc435b5e1 Mon Sep 17 00:00:00 2001 From: nikoscham Date: Fri, 5 Sep 2025 11:03:58 +0300 Subject: [PATCH 07/24] Refactor README and add support section; update usage instructions for Scribbler --- README.md | 21 ++++++++++++++++----- src/solvers/solidHeatTransferScript.js | 1 + 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 471e7ca..0062777 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [FEAScript](https://feascript.com/) is a lightweight finite element simulation library built in JavaScript. It empowers users to create and execute simulations for physics and engineering applications in both browser-based and server-side environments. This is the core library of FEAScript. -> 🚧 **FEAScript is currently under heavy development.** Functionality and interfaces may change rapidly as new features and enhancements are introduced. 🚧 +> 🚧 **FEAScript is currently under heavy development.** Functionality and interfaces may change rapidly as new features and enhancements are introduced. ## Contents @@ -14,9 +14,10 @@ - [JavaScript API](#javascript-api) - [Use FEAScript in the Browser](#use-feascript-in-the-browser) - [Use FEAScript with Node.js](#use-feascript-with-nodejs) - - [Use FEAScript with Online Notebooks](#use-feascript-with-online-notebooks) + - [Use FEAScript with Scribbler](#use-feascript-with-scribbler) - [Visual Editor (FEAScript Platform)](#visual-editor-feascript-platform) - [Quick Example](#quick-example) +- [Support FEAScript](#support-feascript) - [Contributing](#contributing) - [License](#license) @@ -35,7 +36,7 @@ The JavaScript API is the core programmatic interface for FEAScript. Written ent 1. **[In the browser](#use-feascript-in-the-browser)** – Use FEAScript in a simple HTML page where simulations run locally without installations or cloud services. 2. **[With Node.js](#use-feascript-with-nodejs)** – Use FEAScript in server-side JavaScript applications or CLI tools. -3. **[With Online Notebooks](#use-feascript-with-online-notebooks)** – Try FEAScript in interactive JavaScript notebook environments with built-in visualization, such as [Scribbler](https://scribbler.live/). +3. **[With Scribbler](#use-feascript-with-scribbler)** – Use FEAScript in the [Scribbler](https://scribbler.live/) interactive JavaScript notebook environment. ### Use FEAScript in the Browser @@ -86,7 +87,7 @@ When running examples from within this repository, this step is not needed as th 👉 Explore various Node.js examples and use cases [here](https://github.com/FEAScript/FEAScript-core/tree/main/examples). -### Use FEAScript with Online Notebooks +### Use FEAScript with Scribbler FEAScript works well in interactive JavaScript notebook environments, where you can write code, visualize results inline, and share your work with others. [Scribbler](https://scribbler.live/) is one such platform that comes with preloaded scientific libraries, making it an excellent choice for FEAScript simulations. @@ -113,7 +114,7 @@ Here is a minimal browser-based example using the JavaScript API. Adapt paths, s // Import FEAScript library import { FEAScriptModel } from "https://core.feascript.com/dist/feascript.esm.js"; - window.addEventListener("DOMContentLoaded", async () => { + window.addEventListener("DOMContentLoaded", () => { // Create a new FEAScript model const model = new FEAScriptModel(); @@ -147,6 +148,16 @@ Here is a minimal browser-based example using the JavaScript API. Adapt paths, s - "conditionType" should be replaced with an actual boundary condition type such as "constantTemp" - "boundaryIndex" should be replaced with a string identifying the boundary +## Support FEAScript + +> 💖 **If you find FEAScript useful, please consider supporting its development through a donation:** + + + Donate using Liberapay + + +Your support helps ensure the continued development and maintenance of this project. + ## Contributing We warmly welcome contributors to help expand and refine FEAScript. Please see the [CONTRIBUTING.md](./CONTRIBUTING.md) file for detailed guidance on how to contribute. diff --git a/src/solvers/solidHeatTransferScript.js b/src/solvers/solidHeatTransferScript.js index abe16d8..f297f74 100644 --- a/src/solvers/solidHeatTransferScript.js +++ b/src/solvers/solidHeatTransferScript.js @@ -39,6 +39,7 @@ export function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) { } = meshConfig; // Create a new instance of the Mesh class + // TODO: The mesh generation step should be moved outside of the assembleSolidHeatTransferMat function debugLog("Generating mesh..."); let mesh; if (meshDimension === "1D") { From 4d46652b324107fbeb5d59df3cd0e352cec8ae2d Mon Sep 17 00:00:00 2001 From: nikoscham Date: Sat, 6 Sep 2025 15:37:56 +0300 Subject: [PATCH 08/24] Refactor frontPropagationScript and solidHeatTransferScript to utilize new mesh utility functions; streamline mesh preparation and isoparametric mapping processes --- src/mesh/meshUtils.js | 217 ++++++++++++++++++++ src/solvers/frontPropagationScript.js | 265 ++++++++----------------- src/solvers/solidHeatTransferScript.js | 220 ++++++-------------- 3 files changed, 359 insertions(+), 343 deletions(-) create mode 100644 src/mesh/meshUtils.js diff --git a/src/mesh/meshUtils.js b/src/mesh/meshUtils.js new file mode 100644 index 0000000..f2be682 --- /dev/null +++ b/src/mesh/meshUtils.js @@ -0,0 +1,217 @@ +// ______ ______ _____ _ _ // +// | ____| ____| /\ / ____| (_) | | // +// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ // +// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| // +// | | | |____ / ____ \ ____) | (__| | | | |_) | | // +// |_| |______/_/ \_\_____/ \___|_| |_| __/| | // +// | | | | // +// |_| | |_ // +// Website: https://feascript.com/ \__| // + +import { BasisFunctions } from "./basisFunctionsScript.js"; +import { Mesh1D, Mesh2D } from "./meshGenerationScript.js"; +import { NumericalIntegration } from "../methods/numericalIntegrationScript.js"; +import { basicLog, debugLog, errorLog } from "../utilities/loggingScript.js"; + +/** + * Prepares the mesh for finite element analysis + * @param {object} meshConfig - Object containing computational mesh details + * @returns {object} An object containing all mesh-related data + */ +export function prepareMesh(meshConfig) { + const { meshDimension, numElementsX, numElementsY, maxX, maxY, elementOrder, parsedMesh } = meshConfig; + + // Create a new instance of the Mesh class + let mesh; + if (meshDimension === "1D") { + mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh }); + } else if (meshDimension === "2D") { + mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh }); + } else { + errorLog("Mesh dimension must be either '1D' or '2D'."); + } + + // Use the parsed mesh in case it was already passed with Gmsh format + const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh(); + + // Extract nodes coordinates and nodal numbering (NOP) from the mesh data + let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates; + let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates; + let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX; + let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY; + let nop = nodesCoordinatesAndNumbering.nodalNumbering; + let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements; + + // Check the mesh type + const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null; + + // Calculate totalElements and totalNodes based on mesh type + let totalElements, totalNodes; + + if (isParsedMesh) { + totalElements = nop.length; // Number of elements is the length of the nodal numbering array + totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array + debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`); + } else { + // For structured mesh, calculate based on dimensions + totalElements = numElementsX * (meshDimension === "2D" ? numElementsY : 1); + totalNodes = totalNodesX * (meshDimension === "2D" ? totalNodesY : 1); + debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`); + } + + return { + nodesXCoordinates, + nodesYCoordinates, + totalNodesX, + totalNodesY, + nop, + boundaryElements, + totalElements, + totalNodes, + meshDimension, + elementOrder, + }; +} + +/** + * Initializes the FEA matrices and numerical tools + * @param {object} meshData - Object containing mesh data from prepareMesh() + * @returns {object} An object containing initialized matrices and numerical tools + */ +export function initializeFEA(meshData) { + const { totalNodes, nop, meshDimension, elementOrder } = meshData; + + // Initialize variables for matrix assembly + let residualVector = []; + let jacobianMatrix = []; + let localToGlobalMap = []; + + // Initialize jacobianMatrix and residualVector arrays + for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) { + residualVector[nodeIndex] = 0; + jacobianMatrix.push([]); + for (let colIndex = 0; colIndex < totalNodes; colIndex++) { + jacobianMatrix[nodeIndex][colIndex] = 0; + } + } + + // Initialize the BasisFunctions class + const basisFunctions = new BasisFunctions({ + meshDimension, + elementOrder, + }); + + // Initialize the NumericalIntegration class + const numericalIntegration = new NumericalIntegration({ + meshDimension, + elementOrder, + }); + + // Calculate Gauss points and weights + let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights(); + let gaussPoints = gaussPointsAndWeights.gaussPoints; + let gaussWeights = gaussPointsAndWeights.gaussWeights; + + // Determine the number of nodes in the reference element based on the first element in the nop array + const numNodes = nop[0].length; + + return { + residualVector, + jacobianMatrix, + localToGlobalMap, + basisFunctions, + gaussPoints, + gaussWeights, + numNodes, + }; +} + +/** + * Performs isoparametric mapping for 1D elements + * @param {object} params - Parameters for the mapping + * @returns {object} An object containing the mapped data + */ +export function performIsoparametricMapping1D(params) { + const { basisFunction, basisFunctionDerivKsi, nodesXCoordinates, localToGlobalMap, numNodes } = params; + + let xCoordinates = 0; + let ksiDerivX = 0; + + // Isoparametric mapping + for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex]; + ksiDerivX += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex]; + } + let detJacobian = ksiDerivX; + + // Compute x-derivative of basis functions + let basisFunctionDerivX = []; + for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; + } + + return { + xCoordinates, + detJacobian, + basisFunctionDerivX, + }; +} + +/** + * Performs isoparametric mapping for 2D elements + * @param {object} params - Parameters for the mapping + * @returns {object} An object containing the mapped data + */ +export function performIsoparametricMapping2D(params) { + const { + basisFunction, + basisFunctionDerivKsi, + basisFunctionDerivEta, + nodesXCoordinates, + nodesYCoordinates, + localToGlobalMap, + numNodes, + } = params; + + let xCoordinates = 0; + let yCoordinates = 0; + let ksiDerivX = 0; + let etaDerivX = 0; + let ksiDerivY = 0; + let etaDerivY = 0; + + // Isoparametric mapping + for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex]; + yCoordinates += nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex]; + ksiDerivX += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex]; + etaDerivX += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex]; + ksiDerivY += nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex]; + etaDerivY += nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex]; + } + let detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY; + + // Compute x-derivative and y-derivative of basis functions + let basisFunctionDerivX = []; + let basisFunctionDerivY = []; + for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + // The x-derivative of the n basis function + basisFunctionDerivX[localNodeIndex] = + (etaDerivY * basisFunctionDerivKsi[localNodeIndex] - + ksiDerivY * basisFunctionDerivEta[localNodeIndex]) / + detJacobian; + // The y-derivative of the n basis function + basisFunctionDerivY[localNodeIndex] = + (ksiDerivX * basisFunctionDerivEta[localNodeIndex] - + etaDerivX * basisFunctionDerivKsi[localNodeIndex]) / + detJacobian; + } + + return { + xCoordinates, + yCoordinates, + detJacobian, + basisFunctionDerivX, + basisFunctionDerivY, + }; +} diff --git a/src/solvers/frontPropagationScript.js b/src/solvers/frontPropagationScript.js index bd2a649..109d523 100644 --- a/src/solvers/frontPropagationScript.js +++ b/src/solvers/frontPropagationScript.js @@ -9,12 +9,14 @@ // Website: https://feascript.com/ \__| // // Internal imports - import { GenericBoundaryConditions } from "./genericBoundaryConditionsScript.js"; -import { BasisFunctions } from "../mesh/basisFunctionsScript.js"; -import { Mesh1D, Mesh2D } from "../mesh/meshGenerationScript.js"; -import { NumericalIntegration } from "../methods/numericalIntegrationScript.js"; -import { basicLog, debugLog, errorLog } from "../utilities/loggingScript.js"; +import { + prepareMesh, + initializeFEA, + performIsoparametricMapping1D, + performIsoparametricMapping2D, +} from "../mesh/meshUtils.js"; +import { basicLog, debugLog } from "../utilities/loggingScript.js"; /** * Function to assemble the front propagation matrix @@ -35,117 +37,32 @@ export function assembleFrontPropagationMat( ) { basicLog("Starting front propagation matrix assembly..."); + // Calculate eikonal viscous term const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`); basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`); - // Extract mesh details from the configuration object - const { - meshDimension, // The dimension of the mesh - numElementsX, // Number of elements in x-direction - numElementsY, // Number of elements in y-direction (only for 2D) - maxX, // Max x-coordinate (m) of the domain - maxY, // Max y-coordinate (m) of the domain (only for 2D) - elementOrder, // The order of elements - parsedMesh, // The pre-parsed mesh data (if available) - } = meshConfig; - - // Create a new instance of the Mesh class - // TODO: The mesh generation step should be moved outside of the assembleFrontPropagationMat function so that not performed in every Newton-Raphson iteration - debugLog("Generating mesh..."); - let mesh; - if (meshDimension === "1D") { - mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh }); - } else if (meshDimension === "2D") { - mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh }); - } else { - errorLog("Mesh dimension must be either '1D' or '2D'."); - } - - // Use the parsed mesh in case it was already passed with Gmsh format - const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh(); - - // Extract nodes coordinates and nodal numbering (NOP) from the mesh data - let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates; - let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates; - let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX; - let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY; - let nop = nodesCoordinatesAndNumbering.nodalNumbering; - let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements; - - // Check the mesh type - const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null; - - // Calculate totalElements and totalNodes based on mesh type - let totalElements, totalNodes; - - if (isParsedMesh) { - totalElements = nop.length; // Number of elements is the length of the nodal numbering array - totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array - - // Debug log for mesh size - debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`); - } else { - // For structured mesh, calculate based on dimensions - totalElements = numElementsX * (meshDimension === "2D" ? numElementsY : 1); - totalNodes = totalNodesX * (meshDimension === "2D" ? totalNodesY : 1); - // Debug log for mesh size - debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`); - } - - // Initialize variables for matrix assembly - let localToGlobalMap = []; // Maps local element node indices to global mesh node indices - let gaussPoints = []; // Gauss points - let gaussWeights = []; // Gauss weights - let basisFunction = []; // Basis functions - let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi - let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D) - let basisFunctionDerivX = []; // The x-derivative of the basis function - let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D) - let residualVector = []; // Galerkin residuals - let jacobianMatrix = []; // Jacobian matrix - let xCoordinates; // x-coordinate (physical coordinates) - let yCoordinates; // y-coordinate (physical coordinates) (only for 2D) - let ksiDerivX; // ksi-derivative of xCoordinates - let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D) - let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D) - let etaDerivY; // eta-derivative of yCoordinates (only for 2D) - let detJacobian; // The Jacobian of the isoparametric mapping - let solutionDerivX; // The x-derivative of the solution - let solutionDerivY; // The y-derivative of the solution - - // Initialize jacobianMatrix and residualVector arrays - for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) { - residualVector[nodeIndex] = 0; - jacobianMatrix.push([]); - for (let colIndex = 0; colIndex < totalNodes; colIndex++) { - jacobianMatrix[nodeIndex][colIndex] = 0; - } - } - - // Initialize the BasisFunctions class - const basisFunctions = new BasisFunctions({ - meshDimension, - elementOrder, - }); - - // Initialize the NumericalIntegration class - const numericalIntegration = new NumericalIntegration({ - meshDimension, - elementOrder, - }); - - // Calculate Gauss points and weights - let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights(); - gaussPoints = gaussPointsAndWeights.gaussPoints; - gaussWeights = gaussPointsAndWeights.gaussWeights; + // Prepare the mesh + const meshData = prepareMesh(meshConfig); + const { nodesXCoordinates, nodesYCoordinates, nop, boundaryElements, totalElements, meshDimension } = + meshData; - // Determine the number of nodes in the reference element based on the first element in the nop array - const numNodes = nop[0].length; + // Initialize FEA components + const feaData = initializeFEA(meshData); + const { + residualVector, + jacobianMatrix, + localToGlobalMap, + basisFunctions, + gaussPoints, + gaussWeights, + numNodes, + } = feaData; // Matrix assembly for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) { + // Map local element nodes to global mesh nodes for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { // Subtract 1 from nop in order to start numbering from 0 localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1; @@ -155,24 +72,27 @@ export function assembleFrontPropagationMat( for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) { // 1D front propagation (eikonal) equation if (meshDimension === "1D") { + // Get basis functions for the current Gauss point let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]); - basisFunction = basisFunctionsAndDerivatives.basisFunction; - basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi; - xCoordinates = 0; - ksiDerivX = 0; - detJacobian = 0; - - // Isoparametric mapping - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { - xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex]; - ksiDerivX += - nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex]; - detJacobian = ksiDerivX; - } - // Compute x-derivative of basis functions + // Perform isoparametric mapping + const mappingResult = performIsoparametricMapping1D({ + basisFunction: basisFunctionsAndDerivatives.basisFunction, + basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi, + nodesXCoordinates, + localToGlobalMap, + numNodes, + }); + + // Extract mapping results + const { detJacobian, basisFunctionDerivX } = mappingResult; + const basisFunction = basisFunctionsAndDerivatives.basisFunction; + + // Calculate solution derivative + let solutionDerivX = 0; for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { - basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function + solutionDerivX += + solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex]; } // Computation of Galerkin's residuals and Jacobian matrix @@ -187,59 +107,37 @@ export function assembleFrontPropagationMat( // To perform jacobianMatrix calculation here } } - // 2D front propagation (eikonal) equation - } else if (meshDimension === "2D") { + } + // 2D front propagation (eikonal) equation + else if (meshDimension === "2D") { for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) { - // Initialise variables for isoparametric mapping + // Get basis functions for the current Gauss point let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions( gaussPoints[gaussPointIndex1], gaussPoints[gaussPointIndex2] ); - basisFunction = basisFunctionsAndDerivatives.basisFunction; - basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi; - basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta; - xCoordinates = 0; - yCoordinates = 0; - ksiDerivX = 0; - etaDerivX = 0; - ksiDerivY = 0; - etaDerivY = 0; - solutionDerivX = 0; - solutionDerivY = 0; - - // Isoparametric mapping - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { - xCoordinates += - nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex]; - yCoordinates += - nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex]; - ksiDerivX += - nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex]; - etaDerivX += - nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex]; - ksiDerivY += - nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex]; - etaDerivY += - nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex]; - } - detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY; - // Compute x & y-derivatives of basis functions and x & y-derivatives of the solution + // Perform isoparametric mapping + const mappingResult = performIsoparametricMapping2D({ + basisFunction: basisFunctionsAndDerivatives.basisFunction, + basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi, + basisFunctionDerivEta: basisFunctionsAndDerivatives.basisFunctionDerivEta, + nodesXCoordinates, + nodesYCoordinates, + localToGlobalMap, + numNodes, + }); + + // Extract mapping results + const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = mappingResult; + const basisFunction = basisFunctionsAndDerivatives.basisFunction; + + // Calculate solution derivatives + let solutionDerivX = 0; + let solutionDerivY = 0; for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { - // The x-derivative of the n basis function - basisFunctionDerivX[localNodeIndex] = - (etaDerivY * basisFunctionDerivKsi[localNodeIndex] - - ksiDerivY * basisFunctionDerivEta[localNodeIndex]) / - detJacobian; - // The y-derivative of the n basis function - basisFunctionDerivY[localNodeIndex] = - (ksiDerivX * basisFunctionDerivEta[localNodeIndex] - - etaDerivX * basisFunctionDerivKsi[localNodeIndex]) / - detJacobian; - // The x-derivative of the solution solutionDerivX += solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex]; - // The y-derivative of the solution solutionDerivY += solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex]; } @@ -247,6 +145,7 @@ export function assembleFrontPropagationMat( // Computation of Galerkin's residuals and Jacobian matrix for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) { let localToGlobalMap1 = localToGlobalMap[localNodeIndex1]; + // residualVector - Viscous term: Add diffusion contribution to stabilize the solution residualVector[localToGlobalMap1] += eikonalViscousTerm * @@ -261,6 +160,7 @@ export function assembleFrontPropagationMat( detJacobian * basisFunctionDerivY[localNodeIndex1] * solutionDerivY; + // residualVector - Eikonal term: Add the eikonal equation contribution if (eikonalActivationFlag !== 0) { residualVector[localToGlobalMap1] += @@ -275,8 +175,10 @@ export function assembleFrontPropagationMat( detJacobian * basisFunction[localNodeIndex1]); } + for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) { let localToGlobalMap2 = localToGlobalMap[localNodeIndex2]; + // jacobianMatrix - Viscous term: Add the Jacobian contribution from the diffusion term jacobianMatrix[localToGlobalMap1][localToGlobalMap2] += -eikonalViscousTerm * @@ -285,26 +187,27 @@ export function assembleFrontPropagationMat( detJacobian * (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] + basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]); + // jacobianMatrix - Eikonal term: Add the Jacobian contribution from the eikonal equation if (eikonalActivationFlag !== 0) { jacobianMatrix[localToGlobalMap1][localToGlobalMap2] += eikonalActivationFlag * - (-( - (detJacobian * + (-( + detJacobian * solutionDerivX * basisFunction[localNodeIndex1] * gaussWeights[gaussPointIndex1] * - gaussWeights[gaussPointIndex2]) / - Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8) - ) * - basisFunctionDerivX[localNodeIndex2] - - ((detJacobian * - solutionDerivY * - basisFunction[localNodeIndex1] * - gaussWeights[gaussPointIndex1] * - gaussWeights[gaussPointIndex2]) / + gaussWeights[gaussPointIndex2] + ) / Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) * - basisFunctionDerivY[localNodeIndex2]); + basisFunctionDerivX[localNodeIndex2] - + ((detJacobian * + solutionDerivY * + basisFunction[localNodeIndex1] * + gaussWeights[gaussPointIndex1] * + gaussWeights[gaussPointIndex2]) / + Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) * + basisFunctionDerivY[localNodeIndex2]; } } } @@ -313,21 +216,21 @@ export function assembleFrontPropagationMat( } } - // Create an instance of GenericBoundaryConditions + // Apply boundary conditions basicLog("Applying generic boundary conditions..."); const genericBoundaryConditions = new GenericBoundaryConditions( boundaryConditions, boundaryElements, nop, meshDimension, - elementOrder + meshData.elementOrder ); // Impose ConstantValue boundary conditions genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix); basicLog("Constant value boundary conditions applied"); - // Print all residuals + // Print all residuals in debug mode debugLog("Residuals at each node:"); for (let i = 0; i < residualVector.length; i++) { debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`); diff --git a/src/solvers/solidHeatTransferScript.js b/src/solvers/solidHeatTransferScript.js index f297f74..2dd264b 100644 --- a/src/solvers/solidHeatTransferScript.js +++ b/src/solvers/solidHeatTransferScript.js @@ -9,11 +9,14 @@ // Website: https://feascript.com/ \__| // // Internal imports -import { BasisFunctions } from "../mesh/basisFunctionsScript.js"; -import { Mesh1D, Mesh2D } from "../mesh/meshGenerationScript.js"; -import { NumericalIntegration } from "../methods/numericalIntegrationScript.js"; +import { + prepareMesh, + initializeFEA, + performIsoparametricMapping1D, + performIsoparametricMapping2D, +} from "../mesh/meshUtils.js"; import { ThermalBoundaryConditions } from "./thermalBoundaryConditionsScript.js"; -import { basicLog, debugLog, errorLog } from "../utilities/loggingScript.js"; +import { basicLog, debugLog } from "../utilities/loggingScript.js"; /** * Function to assemble the solid heat transfer matrix @@ -27,110 +30,26 @@ import { basicLog, debugLog, errorLog } from "../utilities/loggingScript.js"; export function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) { basicLog("Starting solid heat transfer matrix assembly..."); - // Extract mesh details from the configuration object - const { - meshDimension, // The dimension of the mesh - numElementsX, // Number of elements in x-direction - numElementsY, // Number of elements in y-direction (only for 2D) - maxX, // Max x-coordinate (m) of the domain - maxY, // Max y-coordinate (m) of the domain (only for 2D) - elementOrder, // The order of elements - parsedMesh, // The pre-parsed mesh data (if available) - } = meshConfig; - - // Create a new instance of the Mesh class - // TODO: The mesh generation step should be moved outside of the assembleSolidHeatTransferMat function - debugLog("Generating mesh..."); - let mesh; - if (meshDimension === "1D") { - mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh }); - } else if (meshDimension === "2D") { - mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh }); - } else { - errorLog("Mesh dimension must be either '1D' or '2D'."); - } - - // Use the parsed mesh in case it was already passed with Gmsh format - const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh(); - - // Extract nodes coordinates and nodal numbering (NOP) from the mesh data - let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates; - let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates; - let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX; - let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY; - let nop = nodesCoordinatesAndNumbering.nodalNumbering; - let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements; - - // Check the mesh type - const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null; - - // Calculate totalElements and totalNodes based on mesh type - let totalElements, totalNodes; - - if (isParsedMesh) { - totalElements = nop.length; // Number of elements is the length of the nodal numbering array - totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array - - // Debug log for mesh size - debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`); - } else { - // For structured mesh, calculate based on dimensions - totalElements = numElementsX * (meshDimension === "2D" ? numElementsY : 1); - totalNodes = totalNodesX * (meshDimension === "2D" ? totalNodesY : 1); - // Debug log for mesh size - debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`); - } - - // Initialize variables for matrix assembly - let localToGlobalMap = []; // Maps local element node indices to global mesh node indices - let gaussPoints = []; // Gauss points - let gaussWeights = []; // Gauss weights - let basisFunction = []; // Basis functions - let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi - let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D) - let basisFunctionDerivX = []; // The x-derivative of the basis function - let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D) - let residualVector = []; // Galerkin residuals - let jacobianMatrix = []; // Jacobian matrix - let xCoordinates; // x-coordinate (physical coordinates) - let yCoordinates; // y-coordinate (physical coordinates) (only for 2D) - let ksiDerivX; // ksi-derivative of xCoordinates - let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D) - let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D) - let etaDerivY; // eta-derivative of yCoordinates (only for 2D) - let detJacobian; // The Jacobian of the isoparametric mapping - - // Initialize jacobianMatrix and residualVector arrays - for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) { - residualVector[nodeIndex] = 0; - jacobianMatrix.push([]); - for (let colIndex = 0; colIndex < totalNodes; colIndex++) { - jacobianMatrix[nodeIndex][colIndex] = 0; - } - } - - // Initialize the BasisFunctions class - const basisFunctions = new BasisFunctions({ - meshDimension, - elementOrder, - }); + // Prepare the mesh + const meshData = prepareMesh(meshConfig); + const { nodesXCoordinates, nodesYCoordinates, nop, boundaryElements, totalElements, meshDimension } = + meshData; - // Initialize the NumericalIntegration class - const numericalIntegration = new NumericalIntegration({ - meshDimension, - elementOrder, - }); - - // Calculate Gauss points and weights - let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights(); - gaussPoints = gaussPointsAndWeights.gaussPoints; - gaussWeights = gaussPointsAndWeights.gaussWeights; - - // Determine the number of nodes in the reference element based on the first element in the nop array - const numNodes = nop[0].length; + // Initialize FEA components + const feaData = initializeFEA(meshData); + const { + residualVector, + jacobianMatrix, + localToGlobalMap, + basisFunctions, + gaussPoints, + gaussWeights, + numNodes, + } = feaData; // Matrix assembly for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) { + // Map local element nodes to global mesh nodes for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { // Subtract 1 from nop in order to start numbering from 0 localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1; @@ -140,24 +59,20 @@ export function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) { for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) { // 1D solid heat transfer if (meshDimension === "1D") { + // Get basis functions for the current Gauss point let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]); - basisFunction = basisFunctionsAndDerivatives.basisFunction; - basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi; - xCoordinates = 0; - ksiDerivX = 0; - // Isoparametric mapping - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { - xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex]; - ksiDerivX += - nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex]; - } - detJacobian = ksiDerivX; + // Perform isoparametric mapping + const mappingResult = performIsoparametricMapping1D({ + basisFunction: basisFunctionsAndDerivatives.basisFunction, + basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi, + nodesXCoordinates, + localToGlobalMap, + numNodes, + }); - // Compute x-derivative of basis functions - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { - basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function - } + // Extract mapping results + const { detJacobian, basisFunctionDerivX } = mappingResult; // Computation of Galerkin's residuals and Jacobian matrix for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) { @@ -172,54 +87,29 @@ export function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) { (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]); } } - // 2D solid heat transfer - } else if (meshDimension === "2D") { + } + // 2D solid heat transfer + else if (meshDimension === "2D") { for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) { - // Initialise variables for isoparametric mapping + // Get basis functions for the current Gauss point let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions( gaussPoints[gaussPointIndex1], gaussPoints[gaussPointIndex2] ); - basisFunction = basisFunctionsAndDerivatives.basisFunction; - basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi; - basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta; - xCoordinates = 0; - yCoordinates = 0; - ksiDerivX = 0; - etaDerivX = 0; - ksiDerivY = 0; - etaDerivY = 0; - // Isoparametric mapping - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { - xCoordinates += - nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex]; - yCoordinates += - nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex]; - ksiDerivX += - nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex]; - etaDerivX += - nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex]; - ksiDerivY += - nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex]; - etaDerivY += - nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex]; - } - detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY; + // Perform isoparametric mapping + const mappingResult = performIsoparametricMapping2D({ + basisFunction: basisFunctionsAndDerivatives.basisFunction, + basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi, + basisFunctionDerivEta: basisFunctionsAndDerivatives.basisFunctionDerivEta, + nodesXCoordinates, + nodesYCoordinates, + localToGlobalMap, + numNodes, + }); - // Compute x-derivative and y-derivative of basis functions - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { - // The x-derivative of the n basis function - basisFunctionDerivX[localNodeIndex] = - (etaDerivY * basisFunctionDerivKsi[localNodeIndex] - - ksiDerivY * basisFunctionDerivEta[localNodeIndex]) / - detJacobian; - // The y-derivative of the n basis function - basisFunctionDerivY[localNodeIndex] = - (ksiDerivX * basisFunctionDerivEta[localNodeIndex] - - etaDerivX * basisFunctionDerivKsi[localNodeIndex]) / - detJacobian; - } + // Extract mapping results + const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = mappingResult; // Computation of Galerkin's residuals and Jacobian matrix for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) { @@ -241,14 +131,14 @@ export function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) { } } - // Create an instance of ThermalBoundaryConditions + // Apply boundary conditions basicLog("Applying thermal boundary conditions..."); const thermalBoundaryConditions = new ThermalBoundaryConditions( boundaryConditions, boundaryElements, nop, meshDimension, - elementOrder + meshData.elementOrder ); // Impose Convection boundary conditions @@ -267,6 +157,12 @@ export function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) { thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix); basicLog("Constant temperature boundary conditions applied"); + // Print all residuals in debug mode + debugLog("Residuals at each node:"); + for (let i = 0; i < residualVector.length; i++) { + debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`); + } + basicLog("Solid heat transfer matrix assembly completed"); return { From ea40a2a8f047a37dd766d39c0974ff52e48ed65b Mon Sep 17 00:00:00 2001 From: nikoscham Date: Sat, 6 Sep 2025 15:43:59 +0300 Subject: [PATCH 09/24] Add validation for geometry parameters in Mesh2D class; ensure required parameters are provided when not using a parsed mesh --- src/mesh/meshGenerationScript.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/mesh/meshGenerationScript.js b/src/mesh/meshGenerationScript.js index 5063bbd..1bf08c8 100644 --- a/src/mesh/meshGenerationScript.js +++ b/src/mesh/meshGenerationScript.js @@ -522,11 +522,10 @@ export class Mesh2D extends Mesh { parsedMesh, }); + // Validate geometry parameters (when not using a parsed mesh) if ( - this.numElementsX === null || - this.maxX === null || - this.numElementsY === null || - this.maxY === null + !parsedMesh && + (this.numElementsX === null || this.maxX === null || this.numElementsY === null || this.maxY === null) ) { errorLog( "numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry" @@ -592,7 +591,7 @@ export class Mesh2D extends Mesh { totalNodesY, this.elementOrder ); - + // Find boundary elements const boundaryElements = this.findBoundaryElements(); From 6cefdee82811218d0a6d2432b2947f2a8d9a8ec8 Mon Sep 17 00:00:00 2001 From: nikoscham Date: Sat, 6 Sep 2025 21:46:48 +0300 Subject: [PATCH 10/24] Update logging messages in mesh generation and utility scripts; change debug logs to error logs for unimplemented element type mapping and clarify function descriptions in documentation comments. --- src/mesh/meshGenerationScript.js | 2 +- src/mesh/meshUtils.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mesh/meshGenerationScript.js b/src/mesh/meshGenerationScript.js index 1bf08c8..ec0d711 100644 --- a/src/mesh/meshGenerationScript.js +++ b/src/mesh/meshGenerationScript.js @@ -118,7 +118,7 @@ export class Mesh { this.parsedMesh.nodalNumbering = mappedNodalNumbering; } else if (this.parsedMesh.elementTypes[2]) { - debugLog("Element type is neither triangle nor quad; mapping for this type is not implemented yet."); + errorLog("Element type is neither triangle nor quad; mapping for this type is not implemented yet."); } debugLog( diff --git a/src/mesh/meshUtils.js b/src/mesh/meshUtils.js index f2be682..5be7a38 100644 --- a/src/mesh/meshUtils.js +++ b/src/mesh/meshUtils.js @@ -14,7 +14,7 @@ import { NumericalIntegration } from "../methods/numericalIntegrationScript.js"; import { basicLog, debugLog, errorLog } from "../utilities/loggingScript.js"; /** - * Prepares the mesh for finite element analysis + * Function to prepare the mesh for finite element analysis * @param {object} meshConfig - Object containing computational mesh details * @returns {object} An object containing all mesh-related data */ @@ -74,7 +74,7 @@ export function prepareMesh(meshConfig) { } /** - * Initializes the FEA matrices and numerical tools + * Function to initialize the FEA matrices and numerical tools * @param {object} meshData - Object containing mesh data from prepareMesh() * @returns {object} An object containing initialized matrices and numerical tools */ @@ -127,7 +127,7 @@ export function initializeFEA(meshData) { } /** - * Performs isoparametric mapping for 1D elements + * Function to perform isoparametric mapping for 1D elements * @param {object} params - Parameters for the mapping * @returns {object} An object containing the mapped data */ @@ -158,7 +158,7 @@ export function performIsoparametricMapping1D(params) { } /** - * Performs isoparametric mapping for 2D elements + * Function to perform isoparametric mapping for 2D elements * @param {object} params - Parameters for the mapping * @returns {object} An object containing the mapped data */ From 49869339c0658354f8504443a99c96f494c1fb1c Mon Sep 17 00:00:00 2001 From: nikoscham Date: Mon, 8 Sep 2025 09:12:04 +0300 Subject: [PATCH 11/24] Rename meshUtils.js to meshUtilsScript.js and update imports in solver scripts --- src/mesh/{meshUtils.js => meshUtilsScript.js} | 0 src/solvers/frontPropagationScript.js | 2 +- src/solvers/solidHeatTransferScript.js | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/mesh/{meshUtils.js => meshUtilsScript.js} (100%) diff --git a/src/mesh/meshUtils.js b/src/mesh/meshUtilsScript.js similarity index 100% rename from src/mesh/meshUtils.js rename to src/mesh/meshUtilsScript.js diff --git a/src/solvers/frontPropagationScript.js b/src/solvers/frontPropagationScript.js index 109d523..506c049 100644 --- a/src/solvers/frontPropagationScript.js +++ b/src/solvers/frontPropagationScript.js @@ -15,7 +15,7 @@ import { initializeFEA, performIsoparametricMapping1D, performIsoparametricMapping2D, -} from "../mesh/meshUtils.js"; +} from "../mesh/meshUtilsScript.js"; import { basicLog, debugLog } from "../utilities/loggingScript.js"; /** diff --git a/src/solvers/solidHeatTransferScript.js b/src/solvers/solidHeatTransferScript.js index 2dd264b..2b67c26 100644 --- a/src/solvers/solidHeatTransferScript.js +++ b/src/solvers/solidHeatTransferScript.js @@ -14,7 +14,7 @@ import { initializeFEA, performIsoparametricMapping1D, performIsoparametricMapping2D, -} from "../mesh/meshUtils.js"; +} from "../mesh/meshUtilsScript.js"; import { ThermalBoundaryConditions } from "./thermalBoundaryConditionsScript.js"; import { basicLog, debugLog } from "../utilities/loggingScript.js"; From 0ea8cd2c47049eac3d43423ddb6fb23103b73309 Mon Sep 17 00:00:00 2001 From: nikoscham Date: Mon, 8 Sep 2025 11:11:33 +0300 Subject: [PATCH 12/24] Refactor FEAScript and solver scripts to utilize prepared mesh data; remove helper function for system size calculation --- src/FEAScript.js | 12 ++++++--- src/methods/newtonRaphsonScript.js | 7 +++-- src/solvers/frontPropagationScript.js | 22 +++++++++------ src/solvers/solidHeatTransferScript.js | 18 ++++++++----- src/utilities/helperFunctionsScript.js | 37 -------------------------- 5 files changed, 38 insertions(+), 58 deletions(-) delete mode 100644 src/utilities/helperFunctionsScript.js diff --git a/src/FEAScript.js b/src/FEAScript.js index ec7826a..4210f8f 100644 --- a/src/FEAScript.js +++ b/src/FEAScript.js @@ -11,6 +11,7 @@ // Internal imports import { newtonRaphson } from "./methods/newtonRaphsonScript.js"; import { solveLinearSystem } from "./methods/linearSystemSolverScript.js"; +import { prepareMesh } from "./mesh/meshUtilsScript.js"; import { assembleFrontPropagationMat } from "./solvers/frontPropagationScript.js"; import { assembleSolidHeatTransferMat } from "./solvers/solidHeatTransferScript.js"; import { basicLog, debugLog, errorLog } from "./utilities/loggingScript.js"; @@ -63,16 +64,21 @@ export class FEAScriptModel { let solutionVector = []; let initialSolution = []; let nodesCoordinates = {}; - let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term - Used in frontPropagationScript + let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term (used in assembleFrontPropagationMat) let newtonRaphsonIterations; + // Prepare the mesh + basicLog("Preparing mesh..."); + const meshData = prepareMesh(this.meshConfig); + basicLog("Mesh preparation completed"); + // Select and execute the appropriate solver based on solverConfig basicLog("Beginning solving process..."); console.time("totalSolvingTime"); if (this.solverConfig === "solidHeatTransferScript") { basicLog(`Using solver: ${this.solverConfig}`); ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleSolidHeatTransferMat( - this.meshConfig, + meshData, this.boundaryConditions )); @@ -87,7 +93,7 @@ export class FEAScriptModel { // Create context object with all necessary properties const context = { - meshConfig: this.meshConfig, + meshData: meshData, boundaryConditions: this.boundaryConditions, eikonalActivationFlag: eikonalActivationFlag, solverMethod: this.solverMethod, diff --git a/src/methods/newtonRaphsonScript.js b/src/methods/newtonRaphsonScript.js index 869d832..92852c9 100644 --- a/src/methods/newtonRaphsonScript.js +++ b/src/methods/newtonRaphsonScript.js @@ -12,7 +12,6 @@ import { euclideanNorm } from "../methods/euclideanNormScript.js"; import { solveLinearSystem } from "./linearSystemSolverScript.js"; import { basicLog, debugLog, errorLog } from "../utilities/loggingScript.js"; -import { calculateSystemSize } from "../utilities/helperFunctionsScript.js"; /** * Function to solve a system of nonlinear equations using the Newton-Raphson method @@ -34,8 +33,8 @@ export function newtonRaphson(assembleMat, context, maxIterations = 100, toleran let residualVector = []; let nodesCoordinates = {}; - // Calculate system size directly from meshConfig - let totalNodes = calculateSystemSize(context.meshConfig); + // Calculate system size from meshData instead of meshConfig + let totalNodes = context.meshData.nodesXCoordinates.length; // Initialize arrays with proper size for (let i = 0; i < totalNodes; i++) { @@ -56,7 +55,7 @@ export function newtonRaphson(assembleMat, context, maxIterations = 100, toleran // Compute Jacobian and residual matrices ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleMat( - context.meshConfig, + context.meshData, context.boundaryConditions, solutionVector, // The solution vector is required in the case of a non-linear equation context.eikonalActivationFlag diff --git a/src/solvers/frontPropagationScript.js b/src/solvers/frontPropagationScript.js index 506c049..44a6e6d 100644 --- a/src/solvers/frontPropagationScript.js +++ b/src/solvers/frontPropagationScript.js @@ -20,17 +20,17 @@ import { basicLog, debugLog } from "../utilities/loggingScript.js"; /** * Function to assemble the front propagation matrix - * @param {object} meshConfig - Object containing computational mesh details + * @param {object} meshData - Object containing prepared mesh data * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis * @param {array} solutionVector - The solution vector for non-linear equations - * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation (ranges from 0 to 1) - * @returns {object} An object containing: + * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation + * @returns {object} An object containing: * - jacobianMatrix: The assembled Jacobian matrix * - residualVector: The assembled residual vector * - nodesCoordinates: Object containing x and y coordinates of nodes */ export function assembleFrontPropagationMat( - meshConfig, + meshData, boundaryConditions, solutionVector, eikonalActivationFlag @@ -43,10 +43,16 @@ export function assembleFrontPropagationMat( basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`); basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`); - // Prepare the mesh - const meshData = prepareMesh(meshConfig); - const { nodesXCoordinates, nodesYCoordinates, nop, boundaryElements, totalElements, meshDimension } = - meshData; + // Extract mesh data + const { + nodesXCoordinates, + nodesYCoordinates, + nop, + boundaryElements, + totalElements, + meshDimension, + elementOrder, + } = meshData; // Initialize FEA components const feaData = initializeFEA(meshData); diff --git a/src/solvers/solidHeatTransferScript.js b/src/solvers/solidHeatTransferScript.js index 2b67c26..36cccc6 100644 --- a/src/solvers/solidHeatTransferScript.js +++ b/src/solvers/solidHeatTransferScript.js @@ -20,20 +20,26 @@ import { basicLog, debugLog } from "../utilities/loggingScript.js"; /** * Function to assemble the solid heat transfer matrix - * @param {object} meshConfig - Object containing computational mesh details + * @param {object} meshData - Object containing prepared mesh data * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis * @returns {object} An object containing: * - jacobianMatrix: The assembled Jacobian matrix * - residualVector: The assembled residual vector * - nodesCoordinates: Object containing x and y coordinates of nodes */ -export function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) { +export function assembleSolidHeatTransferMat(meshData, boundaryConditions) { basicLog("Starting solid heat transfer matrix assembly..."); - // Prepare the mesh - const meshData = prepareMesh(meshConfig); - const { nodesXCoordinates, nodesYCoordinates, nop, boundaryElements, totalElements, meshDimension } = - meshData; + // Extract mesh data + const { + nodesXCoordinates, + nodesYCoordinates, + nop, + boundaryElements, + totalElements, + meshDimension, + elementOrder, + } = meshData; // Initialize FEA components const feaData = initializeFEA(meshData); diff --git a/src/utilities/helperFunctionsScript.js b/src/utilities/helperFunctionsScript.js deleted file mode 100644 index 9aed65f..0000000 --- a/src/utilities/helperFunctionsScript.js +++ /dev/null @@ -1,37 +0,0 @@ -// ______ ______ _____ _ _ // -// | ____| ____| /\ / ____| (_) | | // -// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ // -// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| // -// | | | |____ / ____ \ ____) | (__| | | | |_) | | // -// |_| |______/_/ \_\_____/ \___|_| |_| __/| | // -// | | | | // -// |_| | |_ // -// Website: https://feascript.com/ \__| // - -/** - * Helper function to calculate system size from mesh configuration - * @param {object} meshConfig - Mesh configuration object - * @returns {number} Total number of nodes in the system - */ -export function calculateSystemSize(meshConfig) { - const { meshDimension, numElementsX, numElementsY, elementOrder, parsedMesh } = meshConfig; - - if (parsedMesh && parsedMesh.nodesXCoordinates) { - // For parsed meshes (like from GMSH) - return parsedMesh.nodesXCoordinates.length; - } else { - // For geometry-based meshes - let nodesX, - nodesY = 1; - - if (elementOrder === "linear") { - nodesX = numElementsX + 1; - if (meshDimension === "2D") nodesY = numElementsY + 1; - } else if (elementOrder === "quadratic") { - nodesX = 2 * numElementsX + 1; - if (meshDimension === "2D") nodesY = 2 * numElementsY + 1; - } - - return nodesX * nodesY; - } -} From 8f59df914d656649087ee6ef34aaade2704ae759 Mon Sep 17 00:00:00 2001 From: nikoscham Date: Mon, 8 Sep 2025 11:16:44 +0300 Subject: [PATCH 13/24] Refactor frontPropagationScript and solidHeatTransferScript to improve comment clarity; standardize residualVector and jacobianMatrix descriptions and replace meshData.elementOrder with elementOrder --- src/solvers/frontPropagationScript.js | 10 +++++----- src/solvers/solidHeatTransferScript.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/solvers/frontPropagationScript.js b/src/solvers/frontPropagationScript.js index 44a6e6d..af00d9c 100644 --- a/src/solvers/frontPropagationScript.js +++ b/src/solvers/frontPropagationScript.js @@ -152,7 +152,7 @@ export function assembleFrontPropagationMat( for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) { let localToGlobalMap1 = localToGlobalMap[localNodeIndex1]; - // residualVector - Viscous term: Add diffusion contribution to stabilize the solution + // residualVector: Viscous term contribution (to stabilize the solution) residualVector[localToGlobalMap1] += eikonalViscousTerm * gaussWeights[gaussPointIndex1] * @@ -167,7 +167,7 @@ export function assembleFrontPropagationMat( basisFunctionDerivY[localNodeIndex1] * solutionDerivY; - // residualVector - Eikonal term: Add the eikonal equation contribution + // residualVector: Eikonal equation contribution if (eikonalActivationFlag !== 0) { residualVector[localToGlobalMap1] += eikonalActivationFlag * @@ -185,7 +185,7 @@ export function assembleFrontPropagationMat( for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) { let localToGlobalMap2 = localToGlobalMap[localNodeIndex2]; - // jacobianMatrix - Viscous term: Add the Jacobian contribution from the diffusion term + // jacobianMatrix: Viscous term contribution jacobianMatrix[localToGlobalMap1][localToGlobalMap2] += -eikonalViscousTerm * gaussWeights[gaussPointIndex1] * @@ -194,7 +194,7 @@ export function assembleFrontPropagationMat( (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] + basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]); - // jacobianMatrix - Eikonal term: Add the Jacobian contribution from the eikonal equation + // jacobianMatrix: Eikonal equation contribution if (eikonalActivationFlag !== 0) { jacobianMatrix[localToGlobalMap1][localToGlobalMap2] += eikonalActivationFlag * @@ -229,7 +229,7 @@ export function assembleFrontPropagationMat( boundaryElements, nop, meshDimension, - meshData.elementOrder + elementOrder ); // Impose ConstantValue boundary conditions diff --git a/src/solvers/solidHeatTransferScript.js b/src/solvers/solidHeatTransferScript.js index 36cccc6..f6d1478 100644 --- a/src/solvers/solidHeatTransferScript.js +++ b/src/solvers/solidHeatTransferScript.js @@ -144,7 +144,7 @@ export function assembleSolidHeatTransferMat(meshData, boundaryConditions) { boundaryElements, nop, meshDimension, - meshData.elementOrder + elementOrder ); // Impose Convection boundary conditions From 1db10e5f5fed9be29f3fef97d5a043860a7969a6 Mon Sep 17 00:00:00 2001 From: nikoscham Date: Tue, 9 Sep 2025 10:55:10 +0300 Subject: [PATCH 14/24] Refactor frontalSolverScript and update temporaryFrontalTest to use module imports; rename feaData to FEAData for consistency in frontPropagationScript and solidHeatTransferScript --- src/methods/frontalSolverScript.js | 134 ++++++++++--------------- src/methods/temporaryFrontalTest.html | 13 ++- src/solvers/frontPropagationScript.js | 5 +- src/solvers/solidHeatTransferScript.js | 5 +- 4 files changed, 69 insertions(+), 88 deletions(-) diff --git a/src/methods/frontalSolverScript.js b/src/methods/frontalSolverScript.js index fab5ae7..4508665 100644 --- a/src/methods/frontalSolverScript.js +++ b/src/methods/frontalSolverScript.js @@ -1,3 +1,13 @@ +import { + prepareMesh, + initializeFEA, + performIsoparametricMapping1D, + performIsoparametricMapping2D, +} from "../mesh/meshUtilsScript.js"; +import { BasisFunctions } from "../mesh/basisFunctionsScript.js"; +import { ThermalBoundaryConditions } from "../solvers/thermalBoundaryConditionsScript.js"; +import { basicLog, debugLog } from "../utilities/loggingScript.js"; + // Constants const nemax = 1600; const nnmax = 6724; @@ -59,6 +69,9 @@ const fb1 = { ecpiv: Array(2000000).fill(0), }; +// Instantiate shared basis functions handler (biquadratic 2D) +const basisFunctionsLib = new BasisFunctions({ meshDimension: "2D", elementOrder: "quadratic" }); + // Main program logic function main() { console.log("2-D problem. Biquadratic basis functions\n"); @@ -176,61 +189,13 @@ function xycoord() { } } -// Basis functions -function tsfun(x, y) { - const tsfn = { - phi: Array(9).fill(0), - phic: Array(9).fill(0), - phie: Array(9).fill(0), - }; - - const l1 = (c) => 2 * c * c - 3 * c + 1; - const l2 = (c) => -4 * c * c + 4 * c; - const l3 = (c) => 2 * c * c - c; - const dl1 = (c) => 4 * c - 3; - const dl2 = (c) => -8 * c + 4; - const dl3 = (c) => 4 * c - 1; - - tsfn.phi[0] = l1(x) * l1(y); - tsfn.phi[1] = l1(x) * l2(y); - tsfn.phi[2] = l1(x) * l3(y); - tsfn.phi[3] = l2(x) * l1(y); - tsfn.phi[4] = l2(x) * l2(y); - tsfn.phi[5] = l2(x) * l3(y); - tsfn.phi[6] = l3(x) * l1(y); - tsfn.phi[7] = l3(x) * l2(y); - tsfn.phi[8] = l3(x) * l3(y); - - tsfn.phic[0] = l1(y) * dl1(x); - tsfn.phic[1] = l2(y) * dl1(x); - tsfn.phic[2] = l3(y) * dl1(x); - tsfn.phic[3] = l1(y) * dl2(x); - tsfn.phic[4] = l2(y) * dl2(x); - tsfn.phic[5] = l3(y) * dl2(x); - tsfn.phic[6] = l1(y) * dl3(x); - tsfn.phic[7] = l2(y) * dl3(x); - tsfn.phic[8] = l3(y) * dl3(x); - - tsfn.phie[0] = l1(x) * dl1(y); - tsfn.phie[1] = l1(x) * dl2(y); - tsfn.phie[2] = l1(x) * dl3(y); - tsfn.phie[3] = l2(x) * dl1(y); - tsfn.phie[4] = l2(x) * dl2(y); - tsfn.phie[5] = l2(x) * dl3(y); - tsfn.phie[6] = l3(x) * dl1(y); - tsfn.phie[7] = l3(x) * dl2(y); - tsfn.phie[8] = l3(x) * dl3(y); - - return tsfn; -} - // Element stiffness matrix and residuals function abfind() { let ngl = Array(9).fill(0); let tphx = Array(9).fill(0); let tphy = Array(9).fill(0); - // Initialize stiffness matrix + // Zero element matrix for (let i = 0; i < 9; i++) { for (let j = 0; j < 9; j++) { fabf1.estifm[i][j] = 0; @@ -241,68 +206,75 @@ function abfind() { ngl[i] = Math.abs(block1.nop[fabf1.nell - 1][i]); } + // 3x3 Gauss integration (uses existing gauss.gp in [0,1]) for (let j = 0; j < 3; j++) { for (let k = 0; k < 3; k++) { - let ts = tsfun(gauss.gp[j], gauss.gp[k]); - let x1 = 0, - x2 = 0, - y1 = 0, - y2 = 0; + const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } = + basisFunctionsLib.getBasisFunctions(gauss.gp[j], gauss.gp[k]); - for (let n = 0; n < 9; n++) { - x1 += block1.xpt[ngl[n] - 1] * ts.phic[n]; - x2 += block1.xpt[ngl[n] - 1] * ts.phie[n]; - y1 += block1.ypt[ngl[n] - 1] * ts.phic[n]; - y2 += block1.ypt[ngl[n] - 1] * ts.phie[n]; - } + const localToGlobalMap = ngl.map((g) => g - 1); - let dett = x1 * y2 - x2 * y1; + const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({ + basisFunction, + basisFunctionDerivKsi, + basisFunctionDerivEta, + nodesXCoordinates: block1.xpt, + nodesYCoordinates: block1.ypt, + localToGlobalMap, + numNodes: 9, + }); - for (let i = 0; i < 9; i++) { - tphx[i] = (y2 * ts.phic[i] - y1 * ts.phie[i]) / dett; - tphy[i] = (x1 * ts.phie[i] - x2 * ts.phic[i]) / dett; + for (let n = 0; n < 9; n++) { + tphx[n] = basisFunctionDerivX[n]; + tphy[n] = basisFunctionDerivY[n]; } for (let l = 0; l < 9; l++) { for (let m = 0; m < 9; m++) { - fabf1.estifm[l][m] -= gauss.w[j] * gauss.w[k] * dett * (tphx[l] * tphx[m] + tphy[l] * tphy[m]); + fabf1.estifm[l][m] -= + gauss.w[j] * gauss.w[k] * detJacobian * (tphx[l] * tphx[m] + tphy[l] * tphy[m]); } } } } + // Natural boundary contributions (top / lateral) if (block1.ntop[fabf1.nell - 1] !== 1 && block1.nlat[fabf1.nell - 1] !== 1) return; if (block1.ntop[fabf1.nell - 1] === 1) { - for (let k1 = 0; k1 < 3; k1++) { - let ts = tsfun(gauss.gp[k1], 1); - let x = 0, - x1 = 0; + // eta = 1 edge + for (let gpi = 0; gpi < 3; gpi++) { + const { basisFunction, basisFunctionDerivKsi } = basisFunctionsLib.getBasisFunctions(gauss.gp[gpi], 1); + let x = 0, + dx_dksi = 0; for (let n = 0; n < 9; n++) { - x += block1.xpt[ngl[n] - 1] * ts.phi[n]; - x1 += block1.xpt[ngl[n] - 1] * ts.phic[n]; + x += block1.xpt[ngl[n] - 1] * basisFunction[n]; + dx_dksi += block1.xpt[ngl[n] - 1] * basisFunctionDerivKsi[n]; } - for (let k11 of [2, 5, 8]) { - block1.r1[ngl[k11] - 1] -= gauss.w[k1] * x1 * ts.phi[k11] * x; + // Nodes on top edge in local (quadratic) ordering: 2,5,8 + for (let idx of [2, 5, 8]) { + block1.r1[ngl[idx] - 1] -= gauss.w[gpi] * dx_dksi * basisFunction[idx] * x; } } } if (block1.nlat[fabf1.nell - 1] === 1) { - for (let k2 = 0; k2 < 3; k2++) { - let ts = tsfun(1, gauss.gp[k2]); - let y = 0, - y2 = 0; + // ksi = 1 edge + for (let gpi = 0; gpi < 3; gpi++) { + const { basisFunction, basisFunctionDerivEta } = basisFunctionsLib.getBasisFunctions(1, gauss.gp[gpi]); + let y = 0, + dy_deta = 0; for (let n = 0; n < 9; n++) { - y += block1.ypt[ngl[n] - 1] * ts.phi[n]; - y2 += block1.ypt[ngl[n] - 1] * ts.phie[n]; + y += block1.ypt[ngl[n] - 1] * basisFunction[n]; + dy_deta += block1.ypt[ngl[n] - 1] * basisFunctionDerivEta[n]; } - for (let k21 of [6, 7, 8]) { - block1.r1[ngl[k21] - 1] -= gauss.w[k2] * y2 * ts.phi[k21] * y; + // Nodes on right edge in local (quadratic) ordering: 6,7,8 + for (let idx of [6, 7, 8]) { + block1.r1[ngl[idx] - 1] -= gauss.w[gpi] * dy_deta * basisFunction[idx] * y; } } } diff --git a/src/methods/temporaryFrontalTest.html b/src/methods/temporaryFrontalTest.html index f6b378a..0b8622d 100644 --- a/src/methods/temporaryFrontalTest.html +++ b/src/methods/temporaryFrontalTest.html @@ -1 +1,12 @@ - \ No newline at end of file + + + + + Frontal Solver Test + + + + + diff --git a/src/solvers/frontPropagationScript.js b/src/solvers/frontPropagationScript.js index af00d9c..38f37e8 100644 --- a/src/solvers/frontPropagationScript.js +++ b/src/solvers/frontPropagationScript.js @@ -11,7 +11,6 @@ // Internal imports import { GenericBoundaryConditions } from "./genericBoundaryConditionsScript.js"; import { - prepareMesh, initializeFEA, performIsoparametricMapping1D, performIsoparametricMapping2D, @@ -55,7 +54,7 @@ export function assembleFrontPropagationMat( } = meshData; // Initialize FEA components - const feaData = initializeFEA(meshData); + const FEAData = initializeFEA(meshData); const { residualVector, jacobianMatrix, @@ -64,7 +63,7 @@ export function assembleFrontPropagationMat( gaussPoints, gaussWeights, numNodes, - } = feaData; + } = FEAData; // Matrix assembly for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) { diff --git a/src/solvers/solidHeatTransferScript.js b/src/solvers/solidHeatTransferScript.js index f6d1478..42c6e75 100644 --- a/src/solvers/solidHeatTransferScript.js +++ b/src/solvers/solidHeatTransferScript.js @@ -10,7 +10,6 @@ // Internal imports import { - prepareMesh, initializeFEA, performIsoparametricMapping1D, performIsoparametricMapping2D, @@ -42,7 +41,7 @@ export function assembleSolidHeatTransferMat(meshData, boundaryConditions) { } = meshData; // Initialize FEA components - const feaData = initializeFEA(meshData); + const FEAData = initializeFEA(meshData); const { residualVector, jacobianMatrix, @@ -51,7 +50,7 @@ export function assembleSolidHeatTransferMat(meshData, boundaryConditions) { gaussPoints, gaussWeights, numNodes, - } = feaData; + } = FEAData; // Matrix assembly for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) { From d24092b661a93308fe775af007adef7ca6c1e58b Mon Sep 17 00:00:00 2001 From: nikoscham Date: Tue, 9 Sep 2025 11:41:43 +0300 Subject: [PATCH 15/24] Refactor frontalSolverScript to utilize external assembly for heat transfer elements; update temporaryFrontalTest title and description for clarity. --- src/methods/frontalSolverScript.js | 122 +++++++------------------ src/methods/temporaryFrontalTest.html | 3 +- src/solvers/solidHeatTransferScript.js | 91 ++++++++++++++++++ 3 files changed, 125 insertions(+), 91 deletions(-) diff --git a/src/methods/frontalSolverScript.js b/src/methods/frontalSolverScript.js index 4508665..9e0dacc 100644 --- a/src/methods/frontalSolverScript.js +++ b/src/methods/frontalSolverScript.js @@ -1,12 +1,15 @@ -import { - prepareMesh, - initializeFEA, - performIsoparametricMapping1D, - performIsoparametricMapping2D, -} from "../mesh/meshUtilsScript.js"; +// ______ ______ _____ _ _ // +// | ____| ____| /\ / ____| (_) | | // +// | |__ | |__ / \ | (___ ___ ____ _ ____ | |_ // +// | __| | __| / /\ \ \___ \ / __| __| | _ \| __| // +// | | | |____ / ____ \ ____) | (__| | | | |_) | | // +// |_| |______/_/ \_\_____/ \___|_| |_| __/| | // +// | | | | // +// |_| | |_ // +// Website: https://feascript.com/ \__| // + import { BasisFunctions } from "../mesh/basisFunctionsScript.js"; -import { ThermalBoundaryConditions } from "../solvers/thermalBoundaryConditionsScript.js"; -import { basicLog, debugLog } from "../utilities/loggingScript.js"; +import { assembleSolidHeatTransferFront } from "../solvers/solidHeatTransferScript.js"; // Constants const nemax = 1600; @@ -189,94 +192,33 @@ function xycoord() { } } -// Element stiffness matrix and residuals +// Element stiffness matrix and residuals (delegated to external assembly function) function abfind() { - let ngl = Array(9).fill(0); - let tphx = Array(9).fill(0); - let tphy = Array(9).fill(0); - - // Zero element matrix + const elementIndex = fabf1.nell - 1; + + const { estifm, localLoad, ngl } = assembleSolidHeatTransferFront({ + elementIndex, + nop: block1.nop, + xCoordinates: block1.xpt, + yCoordinates: block1.ypt, + basisFunctions: basisFunctionsLib, + gaussPoints: gauss.gp, + gaussWeights: gauss.w, + ntopFlag: block1.ntop[elementIndex] === 1, + nlatFlag: block1.nlat[elementIndex] === 1, + }); + + // Copy element matrix for (let i = 0; i < 9; i++) { for (let j = 0; j < 9; j++) { - fabf1.estifm[i][j] = 0; + fabf1.estifm[i][j] = estifm[i][j]; } } - for (let i = 0; i < 9; i++) { - ngl[i] = Math.abs(block1.nop[fabf1.nell - 1][i]); - } - - // 3x3 Gauss integration (uses existing gauss.gp in [0,1]) - for (let j = 0; j < 3; j++) { - for (let k = 0; k < 3; k++) { - const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } = - basisFunctionsLib.getBasisFunctions(gauss.gp[j], gauss.gp[k]); - - const localToGlobalMap = ngl.map((g) => g - 1); - - const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({ - basisFunction, - basisFunctionDerivKsi, - basisFunctionDerivEta, - nodesXCoordinates: block1.xpt, - nodesYCoordinates: block1.ypt, - localToGlobalMap, - numNodes: 9, - }); - - for (let n = 0; n < 9; n++) { - tphx[n] = basisFunctionDerivX[n]; - tphy[n] = basisFunctionDerivY[n]; - } - - for (let l = 0; l < 9; l++) { - for (let m = 0; m < 9; m++) { - fabf1.estifm[l][m] -= - gauss.w[j] * gauss.w[k] * detJacobian * (tphx[l] * tphx[m] + tphy[l] * tphy[m]); - } - } - } - } - - // Natural boundary contributions (top / lateral) - if (block1.ntop[fabf1.nell - 1] !== 1 && block1.nlat[fabf1.nell - 1] !== 1) return; - - if (block1.ntop[fabf1.nell - 1] === 1) { - // eta = 1 edge - for (let gpi = 0; gpi < 3; gpi++) { - const { basisFunction, basisFunctionDerivKsi } = basisFunctionsLib.getBasisFunctions(gauss.gp[gpi], 1); - - let x = 0, - dx_dksi = 0; - for (let n = 0; n < 9; n++) { - x += block1.xpt[ngl[n] - 1] * basisFunction[n]; - dx_dksi += block1.xpt[ngl[n] - 1] * basisFunctionDerivKsi[n]; - } - - // Nodes on top edge in local (quadratic) ordering: 2,5,8 - for (let idx of [2, 5, 8]) { - block1.r1[ngl[idx] - 1] -= gauss.w[gpi] * dx_dksi * basisFunction[idx] * x; - } - } - } - - if (block1.nlat[fabf1.nell - 1] === 1) { - // ksi = 1 edge - for (let gpi = 0; gpi < 3; gpi++) { - const { basisFunction, basisFunctionDerivEta } = basisFunctionsLib.getBasisFunctions(1, gauss.gp[gpi]); - - let y = 0, - dy_deta = 0; - for (let n = 0; n < 9; n++) { - y += block1.ypt[ngl[n] - 1] * basisFunction[n]; - dy_deta += block1.ypt[ngl[n] - 1] * basisFunctionDerivEta[n]; - } - - // Nodes on right edge in local (quadratic) ordering: 6,7,8 - for (let idx of [6, 7, 8]) { - block1.r1[ngl[idx] - 1] -= gauss.w[gpi] * dy_deta * basisFunction[idx] * y; - } - } + // Accumulate local load into global RHS + for (let a = 0; a < 9; a++) { + const g = ngl[a] - 1; + block1.r1[g] += localLoad[a]; } } diff --git a/src/methods/temporaryFrontalTest.html b/src/methods/temporaryFrontalTest.html index 0b8622d..d49163e 100644 --- a/src/methods/temporaryFrontalTest.html +++ b/src/methods/temporaryFrontalTest.html @@ -2,9 +2,10 @@ - Frontal Solver Test + Frontal Solver Test (External Assembly) +

Running frontal solver with external heat transfer element assembly...

diff --git a/src/solvers/solidHeatTransferScript.js b/src/solvers/solidHeatTransferScript.js index 42c6e75..b829487 100644 --- a/src/solvers/solidHeatTransferScript.js +++ b/src/solvers/solidHeatTransferScript.js @@ -179,3 +179,94 @@ export function assembleSolidHeatTransferMat(meshData, boundaryConditions) { }, }; } + +// Frontal solver element assembly +export function assembleSolidHeatTransferFront({ + elementIndex, + nop, + xCoordinates, + yCoordinates, + basisFunctions, + gaussPoints, + gaussWeights, + ntopFlag = false, + nlatFlag = false, +}) { + const numNodes = 9; // biquadratic 2D + const estifm = Array(numNodes) + .fill() + .map(() => Array(numNodes).fill(0)); + const localLoad = Array(numNodes).fill(0); + + // Global node numbers (1-based in nop) + const ngl = Array(numNodes); + for (let i = 0; i < numNodes; i++) ngl[i] = Math.abs(nop[elementIndex][i]); + + // Volume (conductive) contribution + for (let j = 0; j < gaussPoints.length; j++) { + for (let k = 0; k < gaussPoints.length; k++) { + const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } = + basisFunctions.getBasisFunctions(gaussPoints[j], gaussPoints[k]); + + const localToGlobalMap = ngl.map((g) => g - 1); + + const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({ + basisFunction, + basisFunctionDerivKsi, + basisFunctionDerivEta, + nodesXCoordinates: xCoordinates, + nodesYCoordinates: yCoordinates, + localToGlobalMap, + numNodes, + }); + + for (let a = 0; a < numNodes; a++) { + for (let b = 0; b < numNodes; b++) { + estifm[a][b] -= + gaussWeights[j] * + gaussWeights[k] * + detJacobian * + (basisFunctionDerivX[a] * basisFunctionDerivX[b] + + basisFunctionDerivY[a] * basisFunctionDerivY[b]); + } + } + } + } + + // Legacy natural boundary terms (top edge eta=1; right edge ksi=1) kept as in original frontal version + if (ntopFlag) { + for (let gp = 0; gp < gaussPoints.length; gp++) { + const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(gaussPoints[gp], 1); + let x = 0, + dx_dksi = 0; + for (let n = 0; n < numNodes; n++) { + const g = ngl[n] - 1; + x += xCoordinates[g] * basisFunction[n]; + dx_dksi += xCoordinates[g] * basisFunctionDerivKsi[n]; + } + // Local nodes on top edge: 2,5,8 + for (const idx of [2, 5, 8]) { + localLoad[idx] -= gaussWeights[gp] * dx_dksi * basisFunction[idx] * x; + } + } + } + + if (nlatFlag) { + for (let gp = 0; gp < gaussPoints.length; gp++) { + const { basisFunction, basisFunctionDerivEta } = basisFunctions.getBasisFunctions(1, gaussPoints[gp]); + let y = 0, + dy_deta = 0; + for (let n = 0; n < numNodes; n++) { + const g = ngl[n] - 1; + y += yCoordinates[g] * basisFunction[n]; + dy_deta += yCoordinates[g] * basisFunctionDerivEta[n]; + } + // Local nodes on right edge: 6,7,8 + for (const idx of [6, 7, 8]) { + localLoad[idx] -= gaussWeights[gp] * dy_deta * basisFunction[idx] * y; + } + } + } + + return { estifm, localLoad, ngl }; +} From d72b2093d2dfe91162be117a017915d6af1eae70 Mon Sep 17 00:00:00 2001 From: nikoscham Date: Tue, 9 Sep 2025 14:01:08 +0300 Subject: [PATCH 16/24] Update README.md to clarify JavaScript API section title and improve consistency in naming --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0062777..8f0f47d 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ ## Contents - [Ways to Use FEAScript](#ways-to-use-feascript) -- [JavaScript API](#javascript-api) +- [JavaScript API (FEAScript Core)](#javascript-api-feascript-core) - [Use FEAScript in the Browser](#use-feascript-in-the-browser) - [Use FEAScript with Node.js](#use-feascript-with-nodejs) - [Use FEAScript with Scribbler](#use-feascript-with-scribbler) @@ -25,12 +25,12 @@ FEAScript offers two main approaches to creating simulations: -1. **[JavaScript API](#javascript-api)** – For developers comfortable with coding, providing full programmatic control in browsers, Node.js, or interactive notebooks. +1. **[JavaScript API (FEAScript Core)](#javascript-api-feascript-core)** – For developers comfortable with coding, providing full programmatic control in browsers, Node.js, or interactive notebooks. 2. **[Visual Editor (FEAScript Platform)](#visual-editor-feascript-platform)** – For users who prefer a no-code approach, offering a block-based visual interface built with [Blockly](https://developers.google.com/blockly). Each approach is explained in detail below. -## JavaScript API +## JavaScript API (FEAScript Core) The JavaScript API is the core programmatic interface for FEAScript. Written entirely in pure JavaScript, it runs in three environments: From 6e33ac8e1911ccc932bf0cb80f6c30de6d76cb1d Mon Sep 17 00:00:00 2001 From: nikoscham Date: Thu, 11 Sep 2025 09:59:51 +0300 Subject: [PATCH 17/24] Update README.md to remove commented-out Liberapay badge for cleaner presentation --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8f0f47d..ee2d619 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,8 @@ # FEAScript-core -[![npm version](https://img.shields.io/npm/v/feascript)](https://www.npmjs.com/package/feascript) [![liberapay](https://img.shields.io/liberapay/receives/FEAScript.svg?logo=liberapay)](https://liberapay.com/FEAScript/) +[![npm version](https://img.shields.io/npm/v/feascript)](https://www.npmjs.com/package/feascript) + [FEAScript](https://feascript.com/) is a lightweight finite element simulation library built in JavaScript. It empowers users to create and execute simulations for physics and engineering applications in both browser-based and server-side environments. This is the core library of FEAScript. From 0385e9df7b9e48af2d073854857c542cd0bf9876 Mon Sep 17 00:00:00 2001 From: nikoscham Date: Thu, 11 Sep 2025 11:29:24 +0300 Subject: [PATCH 18/24] Refactor FEAScript and related scripts to improve clarity and modularity; add plotting capabilities to temporaryFrontalTest and enhance logging messages. --- src/FEAScript.js | 18 +++++++-------- src/methods/frontalSolverScript.js | 14 ++++++++++- src/methods/newtonRaphsonScript.js | 2 +- src/methods/temporaryFrontalTest.html | 23 ++++++++++++++++++- src/solvers/frontPropagationScript.js | 2 +- .../genericBoundaryConditionsScript.js | 2 +- src/solvers/solidHeatTransferScript.js | 11 ++++----- .../thermalBoundaryConditionsScript.js | 4 ++-- 8 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/FEAScript.js b/src/FEAScript.js index 4210f8f..d6d580f 100644 --- a/src/FEAScript.js +++ b/src/FEAScript.js @@ -63,24 +63,24 @@ export class FEAScriptModel { let residualVector = []; let solutionVector = []; let initialSolution = []; - let nodesCoordinates = {}; - let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term (used in assembleFrontPropagationMat) - let newtonRaphsonIterations; // Prepare the mesh basicLog("Preparing mesh..."); const meshData = prepareMesh(this.meshConfig); basicLog("Mesh preparation completed"); + // Extract node coordinates from meshData + const nodesCoordinates = { + nodesXCoordinates: meshData.nodesXCoordinates, + nodesYCoordinates: meshData.nodesYCoordinates, + }; + // Select and execute the appropriate solver based on solverConfig basicLog("Beginning solving process..."); console.time("totalSolvingTime"); if (this.solverConfig === "solidHeatTransferScript") { basicLog(`Using solver: ${this.solverConfig}`); - ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleSolidHeatTransferMat( - meshData, - this.boundaryConditions - )); + ({ jacobianMatrix, residualVector } = assembleSolidHeatTransferMat(meshData, this.boundaryConditions)); // Solve the assembled linear system const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector); @@ -90,6 +90,7 @@ export class FEAScriptModel { // Initialize eikonalActivationFlag let eikonalActivationFlag = 0; + const eikonalExteralIterations = 5; // Number of incremental steps for the eikonal equation // Create context object with all necessary properties const context = { @@ -109,14 +110,13 @@ export class FEAScriptModel { context.initialSolution = [...solutionVector]; } + // Solve the assembled non-linear system const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4); // Extract results jacobianMatrix = newtonRaphsonResult.jacobianMatrix; residualVector = newtonRaphsonResult.residualVector; - nodesCoordinates = newtonRaphsonResult.nodesCoordinates; solutionVector = newtonRaphsonResult.solutionVector; - newtonRaphsonIterations = newtonRaphsonResult.iterations; // Increment for next iteration eikonalActivationFlag += 1 / eikonalExteralIterations; diff --git a/src/methods/frontalSolverScript.js b/src/methods/frontalSolverScript.js index 9e0dacc..9b4774a 100644 --- a/src/methods/frontalSolverScript.js +++ b/src/methods/frontalSolverScript.js @@ -614,4 +614,16 @@ function bacsub(ice) { } // Run the program -main(); +// main(); + +// Add an exported wrapper to obtain results for plotting +export function runFrontalSolver() { + main(); + return { + solutionVector: block1.u.slice(0, block1.np), + nodesCoordinates: { + nodesXCoordinates: block1.xpt.slice(0, block1.np), + nodesYCoordinates: block1.ypt.slice(0, block1.np), + }, + }; +} diff --git a/src/methods/newtonRaphsonScript.js b/src/methods/newtonRaphsonScript.js index 92852c9..cf61330 100644 --- a/src/methods/newtonRaphsonScript.js +++ b/src/methods/newtonRaphsonScript.js @@ -14,7 +14,7 @@ import { solveLinearSystem } from "./linearSystemSolverScript.js"; import { basicLog, debugLog, errorLog } from "../utilities/loggingScript.js"; /** - * Function to solve a system of nonlinear equations using the Newton-Raphson method + * Function to solve a system of non-linear equations using the Newton-Raphson method * @param {number} [maxIterations=100] - Maximum number of iterations * @param {number} [tolerance=1e-4] - Convergence tolerance * @returns {object} An object containing: diff --git a/src/methods/temporaryFrontalTest.html b/src/methods/temporaryFrontalTest.html index d49163e..f7d7653 100644 --- a/src/methods/temporaryFrontalTest.html +++ b/src/methods/temporaryFrontalTest.html @@ -3,11 +3,32 @@ Frontal Solver Test (External Assembly) + + + +

Running frontal solver with external heat transfer element assembly...

+
diff --git a/src/solvers/frontPropagationScript.js b/src/solvers/frontPropagationScript.js index 38f37e8..3c3bb8e 100644 --- a/src/solvers/frontPropagationScript.js +++ b/src/solvers/frontPropagationScript.js @@ -18,7 +18,7 @@ import { import { basicLog, debugLog } from "../utilities/loggingScript.js"; /** - * Function to assemble the front propagation matrix + * Function to assemble the Jacobian matrix and residuals vector for the front propagation model * @param {object} meshData - Object containing prepared mesh data * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis * @param {array} solutionVector - The solution vector for non-linear equations diff --git a/src/solvers/genericBoundaryConditionsScript.js b/src/solvers/genericBoundaryConditionsScript.js index 3938ceb..c425b6e 100644 --- a/src/solvers/genericBoundaryConditionsScript.js +++ b/src/solvers/genericBoundaryConditionsScript.js @@ -40,7 +40,7 @@ export class GenericBoundaryConditions { * @param {array} jacobianMatrix - The Jacobian matrix to be modified */ imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) { - basicLog("Applying constant value boundary conditions (Dirichlet type)"); + basicLog("Applying constant value boundary conditions"); if (this.meshDimension === "1D") { Object.keys(this.boundaryConditions).forEach((boundaryKey) => { if (this.boundaryConditions[boundaryKey][0] === "constantValue") { diff --git a/src/solvers/solidHeatTransferScript.js b/src/solvers/solidHeatTransferScript.js index b829487..d4f4bec 100644 --- a/src/solvers/solidHeatTransferScript.js +++ b/src/solvers/solidHeatTransferScript.js @@ -18,13 +18,12 @@ import { ThermalBoundaryConditions } from "./thermalBoundaryConditionsScript.js" import { basicLog, debugLog } from "../utilities/loggingScript.js"; /** - * Function to assemble the solid heat transfer matrix + * Function to assemble the Jacobian matrix and residuals vector for the solid heat transfer model * @param {object} meshData - Object containing prepared mesh data * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis * @returns {object} An object containing: * - jacobianMatrix: The assembled Jacobian matrix * - residualVector: The assembled residual vector - * - nodesCoordinates: Object containing x and y coordinates of nodes */ export function assembleSolidHeatTransferMat(meshData, boundaryConditions) { basicLog("Starting solid heat transfer matrix assembly..."); @@ -173,14 +172,12 @@ export function assembleSolidHeatTransferMat(meshData, boundaryConditions) { return { jacobianMatrix, residualVector, - nodesCoordinates: { - nodesXCoordinates, - nodesYCoordinates, - }, }; } -// Frontal solver element assembly +/** + * Function to assemble the local Jacobian matrix and residuals vector for the solid heat transfer model when using the frontal system solver + */ export function assembleSolidHeatTransferFront({ elementIndex, nop, diff --git a/src/solvers/thermalBoundaryConditionsScript.js b/src/solvers/thermalBoundaryConditionsScript.js index d3f644b..06570d4 100644 --- a/src/solvers/thermalBoundaryConditionsScript.js +++ b/src/solvers/thermalBoundaryConditionsScript.js @@ -37,7 +37,7 @@ export class ThermalBoundaryConditions { * @param {array} jacobianMatrix - The Jacobian matrix to be modified */ imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) { - basicLog("Applying constant temperature boundary conditions (Dirichlet type)"); + basicLog("Applying constant temperature boundary conditions"); if (this.meshDimension === "1D") { Object.keys(this.boundaryConditions).forEach((boundaryKey) => { if (this.boundaryConditions[boundaryKey][0] === "constantTemp") { @@ -172,7 +172,7 @@ export class ThermalBoundaryConditions { nodesYCoordinates, basisFunctions ) { - basicLog("Applying convection boundary conditions (Robin type)"); + basicLog("Applying convection boundary conditions"); // Extract convection parameters from boundary conditions let convectionHeatTranfCoeff = []; let convectionExtTemp = []; From ceb3ebac927a73adf2cf9783f0d26dc81c7a0a79 Mon Sep 17 00:00:00 2001 From: nikoscham Date: Thu, 11 Sep 2025 11:48:15 +0300 Subject: [PATCH 19/24] Update README.md to improve structure and consistency in the JavaScript API section --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index ee2d619..edb785d 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,11 @@ ## Contents - [Ways to Use FEAScript](#ways-to-use-feascript) -- [JavaScript API (FEAScript Core)](#javascript-api-feascript-core) - - [Use FEAScript in the Browser](#use-feascript-in-the-browser) - - [Use FEAScript with Node.js](#use-feascript-with-nodejs) - - [Use FEAScript with Scribbler](#use-feascript-with-scribbler) -- [Visual Editor (FEAScript Platform)](#visual-editor-feascript-platform) + - [JavaScript API (FEAScript Core)](#javascript-api-feascript-core) + - [Use FEAScript in the Browser](#use-feascript-in-the-browser) + - [Use FEAScript with Node.js](#use-feascript-with-nodejs) + - [Use FEAScript with Scribbler](#use-feascript-with-scribbler) + - [Visual Editor (FEAScript Platform)](#visual-editor-feascript-platform) - [Quick Example](#quick-example) - [Support FEAScript](#support-feascript) - [Contributing](#contributing) @@ -31,7 +31,7 @@ FEAScript offers two main approaches to creating simulations: Each approach is explained in detail below. -## JavaScript API (FEAScript Core) +### JavaScript API (FEAScript Core) The JavaScript API is the core programmatic interface for FEAScript. Written entirely in pure JavaScript, it runs in three environments: @@ -39,7 +39,7 @@ The JavaScript API is the core programmatic interface for FEAScript. Written ent 2. **[With Node.js](#use-feascript-with-nodejs)** – Use FEAScript in server-side JavaScript applications or CLI tools. 3. **[With Scribbler](#use-feascript-with-scribbler)** – Use FEAScript in the [Scribbler](https://scribbler.live/) interactive JavaScript notebook environment. -### Use FEAScript in the Browser +#### Use FEAScript in the Browser You can use FEAScript in browser environments in two ways: @@ -63,7 +63,7 @@ You can use FEAScript in browser environments in two ways: 👉 Explore various browser-based examples and use cases on our [website](https://feascript.com/#tutorials). -### Use FEAScript with Node.js +#### Use FEAScript with Node.js Install FEAScript and its peer dependencies from npm: @@ -88,13 +88,13 @@ When running examples from within this repository, this step is not needed as th 👉 Explore various Node.js examples and use cases [here](https://github.com/FEAScript/FEAScript-core/tree/main/examples). -### Use FEAScript with Scribbler +#### Use FEAScript with Scribbler FEAScript works well in interactive JavaScript notebook environments, where you can write code, visualize results inline, and share your work with others. [Scribbler](https://scribbler.live/) is one such platform that comes with preloaded scientific libraries, making it an excellent choice for FEAScript simulations. 👉 Explore various FEAScript examples on [Scribbler Hub](https://hub.scribbler.live/portfolio/#!nikoscham/FEAScript-Scribbler-examples). -## Visual Editor (FEAScript Platform) +### Visual Editor (FEAScript Platform) For users who prefer a visual approach to creating simulations, we offer the [FEAScript platform](https://platform.feascript.com/) - a browser-based visual editor built on the [Blockly](https://developers.google.com/blockly) library. This no-code interface allows you to: From f060111032bebfd16df9274b532abe102f455cc1 Mon Sep 17 00:00:00 2001 From: nikoscham Date: Thu, 11 Sep 2025 13:56:03 +0300 Subject: [PATCH 20/24] Update README.md for improved clarity and consistency in language and structure --- README.md | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index edb785d..3e1a037 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ [![npm version](https://img.shields.io/npm/v/feascript)](https://www.npmjs.com/package/feascript) -[FEAScript](https://feascript.com/) is a lightweight finite element simulation library built in JavaScript. It empowers users to create and execute simulations for physics and engineering applications in both browser-based and server-side environments. This is the core library of FEAScript. +[FEAScript](https://feascript.com/) is a lightweight finite element simulation library built in JavaScript. It empowers users to create and execute simulations for physics and engineering applications in both browser-based and server-side environments. This is the core library of the FEAScript project. -> 🚧 **FEAScript is currently under heavy development.** Functionality and interfaces may change rapidly as new features and enhancements are introduced. +> 🚧 **FEAScript is currently under heavy development.** Its functionality and interfaces may change rapidly as new features and enhancements are introduced. ## Contents @@ -35,7 +35,7 @@ Each approach is explained in detail below. The JavaScript API is the core programmatic interface for FEAScript. Written entirely in pure JavaScript, it runs in three environments: -1. **[In the browser](#use-feascript-in-the-browser)** – Use FEAScript in a simple HTML page where simulations run locally without installations or cloud services. +1. **[In the browser](#use-feascript-in-the-browser)** – Use FEAScript in a simple HTML page, running simulations locally without additional installations or cloud services. 2. **[With Node.js](#use-feascript-with-nodejs)** – Use FEAScript in server-side JavaScript applications or CLI tools. 3. **[With Scribbler](#use-feascript-with-scribbler)** – Use FEAScript in the [Scribbler](https://scribbler.live/) interactive JavaScript notebook environment. @@ -61,11 +61,11 @@ You can use FEAScript in browser environments in two ways: ``` -👉 Explore various browser-based examples and use cases on our [website](https://feascript.com/#tutorials). +👉 Explore browser-based tutorials on our [website](https://feascript.com/#tutorials). #### Use FEAScript with Node.js -Install FEAScript and its peer dependencies from npm: +Install FEAScript and its peer dependencies from npm as follows: ```bash npm install feascript mathjs plotly.js @@ -84,25 +84,27 @@ import { FEAScriptModel } from "feascript"; echo '{"type":"module"}' > package.json ``` -When running examples from within this repository, this step is not needed as the root package.json already has the proper configuration. +When running examples from within this repository, this step isn’t needed as the root package.json already has the proper configuration. -👉 Explore various Node.js examples and use cases [here](https://github.com/FEAScript/FEAScript-core/tree/main/examples). +👉 Explore Node.js use cases on the [examples directory](https://github.com/FEAScript/FEAScript-core/tree/main/examples). #### Use FEAScript with Scribbler -FEAScript works well in interactive JavaScript notebook environments, where you can write code, visualize results inline, and share your work with others. [Scribbler](https://scribbler.live/) is one such platform that comes with preloaded scientific libraries, making it an excellent choice for FEAScript simulations. +FEAScript also works well in interactive JavaScript notebook environments where you can write code, visualize results inline, and share your work with others. [Scribbler](https://scribbler.live/) is one such platform that comes with preloaded scientific libraries, making it an excellent choice for FEAScript simulations. -👉 Explore various FEAScript examples on [Scribbler Hub](https://hub.scribbler.live/portfolio/#!nikoscham/FEAScript-Scribbler-examples). +👉 Explore FEAScript notebook examples on the [Scribbler Hub](https://hub.scribbler.live/portfolio/#!nikoscham/FEAScript-Scribbler-examples). ### Visual Editor (FEAScript Platform) -For users who prefer a visual approach to creating simulations, we offer the [FEAScript platform](https://platform.feascript.com/) - a browser-based visual editor built on the [Blockly](https://developers.google.com/blockly) library. This no-code interface allows you to: +For users who prefer a visual approach to creating simulations, we offer the [FEAScript Platform](https://platform.feascript.com/) - a browser-based visual editor built on the [Blockly](https://developers.google.com/blockly) library. This no-code interface allows you to: -- Build and run finite element simulations directly in your browser by connecting visual blocks +- Build and run finite element simulations directly in your browser by connecting visual blocks together - Create complex simulations without writing any JavaScript code - Save and load projects in XML format for easy sharing and reuse -While FEAScript's JavaScript API offers full programmatic control for advanced customization, the FEAScript platform provides an accessible entry point for users without coding experience. +While FEAScript's JavaScript API offers full programmatic control for advanced customization, the FEAScript Platform provides an accessible entry point for users without coding experience. + +👉 Explore various FEAScript Platform examples on our [website](https://feascript.com/#tutorials). ## Quick Example @@ -124,8 +126,8 @@ Here is a minimal browser-based example using the JavaScript API. Adapt paths, s // Configure the mesh model.setMeshConfig({ - meshDimension: "1D", // Choose either: "1D" or "2D" - elementOrder: "linear", // Choose either: "linear" or "quadratic" + meshDimension: "1D", // Choose either "1D" or "2D" + elementOrder: "linear", // Choose either "linear" or "quadratic" numElementsX: 10, // Number of elements in x-direction numElementsY: 6, // Number of elements in y-direction (for 2D only) maxX: 1.0, // Domain length in x-direction @@ -139,7 +141,7 @@ Here is a minimal browser-based example using the JavaScript API. Adapt paths, s const { solutionVector, nodesCoordinates } = model.solve(); }); - + ``` From 3b7ededb5c4eb7784f6711606c7b8ed67e07cf8c Mon Sep 17 00:00:00 2001 From: nikoscham Date: Thu, 11 Sep 2025 21:24:11 +0300 Subject: [PATCH 21/24] Update README.md for formatting consistency; remove unused nodesCoordinates in newtonRaphsonScript.js and frontPropagationScript.js --- README.md | 5 +++-- src/methods/frontalSolverScript.js | 1 + src/methods/newtonRaphsonScript.js | 6 ++---- src/solvers/frontPropagationScript.js | 5 ----- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 3e1a037..80c8b56 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,8 @@ # FEAScript-core -[![npm version](https://img.shields.io/npm/v/feascript)](https://www.npmjs.com/package/feascript) +[![npm version](https://img.shields.io/npm/v/feascript)](https://www.npmjs.com/package/feascript) + [FEAScript](https://feascript.com/) is a lightweight finite element simulation library built in JavaScript. It empowers users to create and execute simulations for physics and engineering applications in both browser-based and server-side environments. This is the core library of the FEAScript project. @@ -104,7 +105,7 @@ For users who prefer a visual approach to creating simulations, we offer the [FE While FEAScript's JavaScript API offers full programmatic control for advanced customization, the FEAScript Platform provides an accessible entry point for users without coding experience. -👉 Explore various FEAScript Platform examples on our [website](https://feascript.com/#tutorials). +👉 Explore FEAScript Platform examples on our [website](https://feascript.com/#tutorials). ## Quick Example diff --git a/src/methods/frontalSolverScript.js b/src/methods/frontalSolverScript.js index 9b4774a..73c38f8 100644 --- a/src/methods/frontalSolverScript.js +++ b/src/methods/frontalSolverScript.js @@ -8,6 +8,7 @@ // |_| | |_ // // Website: https://feascript.com/ \__| // +// Internal imports import { BasisFunctions } from "../mesh/basisFunctionsScript.js"; import { assembleSolidHeatTransferFront } from "../solvers/solidHeatTransferScript.js"; diff --git a/src/methods/newtonRaphsonScript.js b/src/methods/newtonRaphsonScript.js index cf61330..a9e57e9 100644 --- a/src/methods/newtonRaphsonScript.js +++ b/src/methods/newtonRaphsonScript.js @@ -31,7 +31,6 @@ export function newtonRaphson(assembleMat, context, maxIterations = 100, toleran let solutionVector = []; let jacobianMatrix = []; let residualVector = []; - let nodesCoordinates = {}; // Calculate system size from meshData instead of meshConfig let totalNodes = context.meshData.nodesXCoordinates.length; @@ -54,11 +53,11 @@ export function newtonRaphson(assembleMat, context, maxIterations = 100, toleran } // Compute Jacobian and residual matrices - ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleMat( + ({ jacobianMatrix, residualVector } = assembleMat( context.meshData, context.boundaryConditions, solutionVector, // The solution vector is required in the case of a non-linear equation - context.eikonalActivationFlag + context.eikonalActivationFlag // Currently used only in the front propagation solver (TODO refactor in case of a solver not needing it) )); // Solve the linear system based on the specified solver method @@ -87,6 +86,5 @@ export function newtonRaphson(assembleMat, context, maxIterations = 100, toleran iterations, jacobianMatrix, residualVector, - nodesCoordinates, }; } diff --git a/src/solvers/frontPropagationScript.js b/src/solvers/frontPropagationScript.js index 3c3bb8e..512c816 100644 --- a/src/solvers/frontPropagationScript.js +++ b/src/solvers/frontPropagationScript.js @@ -26,7 +26,6 @@ import { basicLog, debugLog } from "../utilities/loggingScript.js"; * @returns {object} An object containing: * - jacobianMatrix: The assembled Jacobian matrix * - residualVector: The assembled residual vector - * - nodesCoordinates: Object containing x and y coordinates of nodes */ export function assembleFrontPropagationMat( meshData, @@ -246,9 +245,5 @@ export function assembleFrontPropagationMat( return { jacobianMatrix, residualVector, - nodesCoordinates: { - nodesXCoordinates, - nodesYCoordinates, - }, }; } From 1b657647411a5c1f544cdb4dde576bfbceb8abca Mon Sep 17 00:00:00 2001 From: nikoscham Date: Fri, 12 Sep 2025 10:59:05 +0300 Subject: [PATCH 22/24] Add frontal solver integration and enhance solid heat transfer assembly - Introduced frontal solver method in FEAScriptModel for improved solving capabilities. - Added runFrontalSolver function to frontalSolverScript.js for result handling. - Enhanced solidHeatTransferScript.js to support convection boundary conditions. - Removed temporaryFrontalTest.html as it is no longer needed. --- src/FEAScript.js | 20 +++- src/methods/frontalSolverScript.js | 129 ++++++++++++++++--------- src/methods/temporaryFrontalTest.html | 34 ------- src/solvers/solidHeatTransferScript.js | 53 +++++----- 4 files changed, 126 insertions(+), 110 deletions(-) delete mode 100644 src/methods/temporaryFrontalTest.html diff --git a/src/FEAScript.js b/src/FEAScript.js index d6d580f..0e96bdf 100644 --- a/src/FEAScript.js +++ b/src/FEAScript.js @@ -14,6 +14,7 @@ import { solveLinearSystem } from "./methods/linearSystemSolverScript.js"; import { prepareMesh } from "./mesh/meshUtilsScript.js"; import { assembleFrontPropagationMat } from "./solvers/frontPropagationScript.js"; import { assembleSolidHeatTransferMat } from "./solvers/solidHeatTransferScript.js"; +import { runFrontalSolver } from "./methods/frontalSolverScript.js"; import { basicLog, debugLog, errorLog } from "./utilities/loggingScript.js"; /** @@ -80,11 +81,22 @@ export class FEAScriptModel { console.time("totalSolvingTime"); if (this.solverConfig === "solidHeatTransferScript") { basicLog(`Using solver: ${this.solverConfig}`); - ({ jacobianMatrix, residualVector } = assembleSolidHeatTransferMat(meshData, this.boundaryConditions)); - // Solve the assembled linear system - const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector); - solutionVector = linearSystemResult.solutionVector; + // Check if using frontal solver + if (this.solverMethod === "frontal") { + basicLog(`Using frontal solver method`); + // Call frontal solver + const frontalResult = runFrontalSolver(this.meshConfig, this.boundaryConditions); + solutionVector = frontalResult.solutionVector; + } else { + // Use regular linear solver methods + ({ jacobianMatrix, residualVector } = assembleSolidHeatTransferMat( + meshData, + this.boundaryConditions + )); + const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector); + solutionVector = linearSystemResult.solutionVector; + } } else if (this.solverConfig === "frontPropagationScript") { basicLog(`Using solver: ${this.solverConfig}`); diff --git a/src/methods/frontalSolverScript.js b/src/methods/frontalSolverScript.js index 73c38f8..dc3f1fc 100644 --- a/src/methods/frontalSolverScript.js +++ b/src/methods/frontalSolverScript.js @@ -11,6 +11,19 @@ // Internal imports import { BasisFunctions } from "../mesh/basisFunctionsScript.js"; import { assembleSolidHeatTransferFront } from "../solvers/solidHeatTransferScript.js"; +import { basicLog, debugLog, errorLog } from "../utilities/loggingScript.js"; + +// Add an exported wrapper to obtain results for plotting +export function runFrontalSolver(meshConfig, boundaryConditions) { + main(meshConfig, boundaryConditions); + return { + solutionVector: block1.u.slice(0, block1.np), + nodesCoordinates: { + nodesXCoordinates: block1.xpt.slice(0, block1.np), + nodesYCoordinates: block1.ypt.slice(0, block1.np), + }, + }; +} // Constants const nemax = 1600; @@ -77,28 +90,64 @@ const fb1 = { const basisFunctionsLib = new BasisFunctions({ meshDimension: "2D", elementOrder: "quadratic" }); // Main program logic -function main() { - console.log("2-D problem. Biquadratic basis functions\n"); - xydiscr(); +function main(meshConfig, boundaryConditions) { + // console.log("2-D problem. Biquadratic basis functions\n"); + + xydiscr(meshConfig); nodnumb(); xycoord(); - console.log(`nex=${block1.nex} ney=${block1.ney} ne=${block1.ne} np=${block1.np}\n`); + // console.log(`nex=${block1.nex} ney=${block1.ney} ne=${block1.ne} np=${block1.np}\n`); - // Prepare essential boundary conditions + // Initialize all nodes with no boundary condition for (let i = 0; i < block1.np; i++) { block1.ncod[i] = 0; block1.bc[i] = 0; } - for (let i = 0; i < block1.nny; i++) { - block1.ncod[i] = 1; - block1.bc[i] = 0; - } + // Apply boundary conditions based on the boundaryConditions parameter + Object.keys(boundaryConditions).forEach((boundaryKey) => { + const condition = boundaryConditions[boundaryKey]; + + // Handle constantTemp (Dirichlet) boundary conditions + if (condition[0] === "constantTemp") { + const tempValue = boundaryConditions[boundaryKey][1]; + + // Apply boundary condition to the appropriate nodes based on boundary key + switch (boundaryKey) { + case "0": // Bottom boundary (y = yorigin) + for (let col = 0; col < block1.nnx; col++) { + const nodeIndex = col * block1.nny; + block1.ncod[nodeIndex] = 1; + block1.bc[nodeIndex] = tempValue; + } + break; - for (let i = 0; i < block1.np; i += block1.nny) { - block1.ncod[i] = 1; - block1.bc[i] = 0; - } + case "1": // Right boundary (x = xlast) + for (let j = 0; j < block1.nny; j++) { + block1.ncod[j] = 1; + block1.bc[j] = tempValue; + } + break; + + case "2": // Top boundary (y = ylast) + for (let col = 0; col < block1.nnx; col++) { + const nodeIndex = col * block1.nny + (block1.nny - 1); + block1.ncod[nodeIndex] = 1; + block1.bc[nodeIndex] = tempValue; + } + break; + + case "3": // Left boundary (x = xorigin) + for (let j = 0; j < block1.nny; j++) { + const nodeIndex = (block1.nnx - 1) * block1.nny + j; + block1.ncod[nodeIndex] = 1; + block1.bc[nodeIndex] = tempValue; + } + break; + } + } + // Other boundary condition types can be handled later if needed + }); // Prepare natural boundary conditions for (let i = 0; i < block1.ne; i++) { @@ -106,13 +155,13 @@ function main() { block1.nlat[i] = 0; } - for (let i = block1.ney - 1; i < block1.ne; i += block1.ney) { - block1.ntop[i] = 1; - } + // for (let i = block1.ney - 1; i < block1.ne; i += block1.ney) { + // block1.ntop[i] = 1; + // } - for (let i = block1.ne - block1.ney; i < block1.ne; i++) { - block1.nlat[i] = 1; - } + // for (let i = block1.ne - block1.ney; i < block1.ne; i++) { + // block1.nlat[i] = 1; + // } // Initialization for (let i = 0; i < block1.np; i++) { @@ -137,20 +186,23 @@ function main() { // Output results to console for (let i = 0; i < block1.np; i++) { - console.log( + debugLog( `${block1.xpt[i].toExponential(5)} ${block1.ypt[i].toExponential(5)} ${block1.u[i].toExponential(5)}` ); } } // Discretization -function xydiscr() { - block1.nex = 12; - block1.ney = 8; +function xydiscr(meshConfig) { + // Extract values from meshConfig + const { meshDimension, numElementsX, numElementsY, maxX, maxY, elementOrder, parsedMesh } = meshConfig; + + block1.nex = numElementsX; + block1.ney = numElementsY; block1.xorigin = 0; block1.yorigin = 0; - block1.xlast = 1; - block1.ylast = 1; + block1.xlast = maxX; + block1.ylast = maxY; block1.deltax = (block1.xlast - block1.xorigin) / block1.nex; block1.deltay = (block1.ylast - block1.yorigin) / block1.ney; } @@ -332,7 +384,7 @@ function front() { } if (krow > nmax || lcol > nmax) { - console.error("Error: nmax-nsum not large enough"); + errorLog("Error: nmax-nsum not large enough"); return; } @@ -383,7 +435,7 @@ function front() { if (lc > nsum || fabf1.nell < block1.ne) { if (lc === 0) { - console.error("Error: no more rows fully summed"); + errorLog("Error: no more rows fully summed"); return; } @@ -418,7 +470,7 @@ function front() { } if (Math.abs(pivot) < 1e-10) { - console.warn( + errorLog( `Warning: matrix singular or ill-conditioned, nell=${fabf1.nell}, kro=${kro}, lco=${lco}, pivot=${pivot}` ); } @@ -534,7 +586,7 @@ function front() { fb1.qq[0] = 1; if (Math.abs(pivot) < 1e-10) { - console.warn( + errorLog( `Warning: matrix singular or ill-conditioned, nell=${fabf1.nell}, kro=${kro}, lco=${lco}, pivot=${pivot}` ); } @@ -560,7 +612,7 @@ function front() { ipiv++; fro1.ice1 = ice; - if (fro1.iwr1 === 1) console.log(`total ecs transfer in matrix reduction=${ice}`); + if (fro1.iwr1 === 1) debugLog(`total ecs transfer in matrix reduction=${ice}`); bacsub(ice); break; @@ -611,20 +663,5 @@ function bacsub(ice) { block1.ncod[lco - 1] = 1; } - if (fro1.iwr1 === 1) console.log(`value of ice after backsubstitution=${ice}`); -} - -// Run the program -// main(); - -// Add an exported wrapper to obtain results for plotting -export function runFrontalSolver() { - main(); - return { - solutionVector: block1.u.slice(0, block1.np), - nodesCoordinates: { - nodesXCoordinates: block1.xpt.slice(0, block1.np), - nodesYCoordinates: block1.ypt.slice(0, block1.np), - }, - }; + if (fro1.iwr1 === 1) debugLog(`value of ice after backsubstitution=${ice}`); } diff --git a/src/methods/temporaryFrontalTest.html b/src/methods/temporaryFrontalTest.html deleted file mode 100644 index f7d7653..0000000 --- a/src/methods/temporaryFrontalTest.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - Frontal Solver Test (External Assembly) - - - - - - -

Running frontal solver with external heat transfer element assembly...

-
- - - diff --git a/src/solvers/solidHeatTransferScript.js b/src/solvers/solidHeatTransferScript.js index d4f4bec..8c6fe1c 100644 --- a/src/solvers/solidHeatTransferScript.js +++ b/src/solvers/solidHeatTransferScript.js @@ -188,6 +188,7 @@ export function assembleSolidHeatTransferFront({ gaussWeights, ntopFlag = false, nlatFlag = false, + convectionTop = { active: false, coeff: 0, extTemp: 0 }, // NEW }) { const numNodes = 9; // biquadratic 2D const estifm = Array(numNodes) @@ -231,39 +232,39 @@ export function assembleSolidHeatTransferFront({ } // Legacy natural boundary terms (top edge eta=1; right edge ksi=1) kept as in original frontal version - if (ntopFlag) { + // Replace previous generic top-edge load term with explicit Robin (convection) if requested + if (ntopFlag && convectionTop.active) { + const h = convectionTop.coeff; + const Text = convectionTop.extTemp; + // Integrate along top edge (eta = 1); local top edge nodes: 2,5,8 for (let gp = 0; gp < gaussPoints.length; gp++) { - const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(gaussPoints[gp], 1); - let x = 0, - dx_dksi = 0; - for (let n = 0; n < numNodes; n++) { - const g = ngl[n] - 1; - x += xCoordinates[g] * basisFunction[n]; + const ksi = gaussPoints[gp]; + const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(ksi, 1); + + // Compute metric (edge length differential) |dx/dksi| + let dx_dksi = 0, dy_dksi = 0; + const topEdgeLocalNodes = [2, 5, 8]; + for (let n = 0; n < 9; n++) { + const g = nop[elementIndex][n] - 1; dx_dksi += xCoordinates[g] * basisFunctionDerivKsi[n]; + dy_dksi += yCoordinates[g] * basisFunctionDerivKsi[n]; } - // Local nodes on top edge: 2,5,8 - for (const idx of [2, 5, 8]) { - localLoad[idx] -= gaussWeights[gp] * dx_dksi * basisFunction[idx] * x; - } - } - } + const ds_dksi = Math.sqrt(dx_dksi * dx_dksi + dy_dksi * dy_dksi); - if (nlatFlag) { - for (let gp = 0; gp < gaussPoints.length; gp++) { - const { basisFunction, basisFunctionDerivEta } = basisFunctions.getBasisFunctions(1, gaussPoints[gp]); - let y = 0, - dy_deta = 0; - for (let n = 0; n < numNodes; n++) { - const g = ngl[n] - 1; - y += yCoordinates[g] * basisFunction[n]; - dy_deta += yCoordinates[g] * basisFunctionDerivEta[n]; - } - // Local nodes on right edge: 6,7,8 - for (const idx of [6, 7, 8]) { - localLoad[idx] -= gaussWeights[gp] * dy_deta * basisFunction[idx] * y; + // Assemble Robin contributions + for (const a of topEdgeLocalNodes) { + for (const b of topEdgeLocalNodes) { + estifm[a][b] -= gaussWeights[gp] * ds_dksi * h * basisFunction[a] * basisFunction[b]; + } + localLoad[a] -= gaussWeights[gp] * ds_dksi * h * Text * basisFunction[a]; } } + } else if (ntopFlag && !convectionTop.active) { + // If a zero-flux (symmetry) condition were applied on top, do nothing (natural BC) + // (Previous placeholder load term removed to avoid unintended flux) } + // If needed, similar patterned handling could be added for right edge (nlatFlag) later. + return { estifm, localLoad, ngl }; } From f898d84336211747f4870e7b6c6adcf94134ce88 Mon Sep 17 00:00:00 2001 From: nikoscham Date: Fri, 12 Sep 2025 13:29:01 +0300 Subject: [PATCH 23/24] Refactor LU solver implementation to use sparse matrix for improved performance --- src/methods/linearSystemSolverScript.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/methods/linearSystemSolverScript.js b/src/methods/linearSystemSolverScript.js index 0fa0bec..ffe15d3 100644 --- a/src/methods/linearSystemSolverScript.js +++ b/src/methods/linearSystemSolverScript.js @@ -38,7 +38,11 @@ export function solveLinearSystem(solverMethod, jacobianMatrix, residualVector, if (solverMethod === "lusolve") { // Use LU decomposition method - solutionVector = math.lusolve(jacobianMatrix, residualVector); + const jacobianMatrixSparse = math.sparse(jacobianMatrix); + const luFactorization = math.slu(jacobianMatrixSparse, 1, 1); // order=1, threshold=1 for pivoting + let solutionMatrix = math.lusolve(luFactorization, residualVector); + solutionVector = math.squeeze(solutionMatrix).valueOf(); + //solutionVector = math.lusolve(jacobianMatrix, residualVector); // In the case of a dense matrix } else if (solverMethod === "jacobi") { // Use Jacobi method const initialGuess = new Array(residualVector.length).fill(0); From 9c1ed7f861494e8a90e2fc52da22dd3b7297b378 Mon Sep 17 00:00:00 2001 From: nikoscham Date: Fri, 12 Sep 2025 13:49:56 +0300 Subject: [PATCH 24/24] Build new npm package --- dist/feascript.cjs.js | 4 ++-- dist/feascript.cjs.js.map | 2 +- dist/feascript.esm.js | 4 ++-- dist/feascript.esm.js.map | 2 +- dist/feascript.umd.js | 4 ++-- dist/feascript.umd.js.map | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dist/feascript.cjs.js b/dist/feascript.cjs.js index bc914b9..a415618 100644 --- a/dist/feascript.cjs.js +++ b/dist/feascript.cjs.js @@ -1,8 +1,8 @@ -"use strict";function e(e){let t=0;for(let n=0;n100){o(`Solution not converged. Error norm: ${l}`);break}m++}return{solutionVector:u,converged:d,iterations:m,jacobianMatrix:c,residualVector:f,nodesCoordinates:p}}class a{constructor(e,t,n,s,o){this.boundaryConditions=e,this.boundaryElements=t,this.nop=n,this.meshDimension=s,this.elementOrder=o}imposeConstantValueBoundaryConditions(e,t){s("Applying constant value boundary conditions (Dirichlet type)"),"1D"===this.meshDimension?Object.keys(this.boundaryConditions).forEach((s=>{if("constantValue"===this.boundaryConditions[s][0]){const o=this.boundaryConditions[s][1];n(`Boundary ${s}: Applying constant value of ${o} (Dirichlet condition)`),this.boundaryElements[s].forEach((([s,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[s][i]-1;n(` - Applied constant value to node ${r+1} (element ${s+1}, local node ${i+1})`),e[r]=o;for(let n=0;n{const r=this.nop[s][i]-1;n(` - Applied constant value to node ${r+1} (element ${s+1}, local node ${i+1})`),e[r]=o;for(let n=0;n{if("constantValue"===this.boundaryConditions[s][0]){const o=this.boundaryConditions[s][1];n(`Boundary ${s}: Applying constant value of ${o} (Dirichlet condition)`),this.boundaryElements[s].forEach((([s,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[s][i]-1;n(` - Applied constant value to node ${r+1} (element ${s+1}, local node ${i+1})`),e[r]=o;for(let n=0;n{const r=this.nop[s][i]-1;n(` - Applied constant value to node ${r+1} (element ${s+1}, local node ${i+1})`),e[r]=o;for(let n=0;n0&&void 0===this.parsedMesh.boundaryElements[0]){const e=[];for(let t=1;t{if(1===e.dimension){const t=this.parsedMesh.boundaryNodePairs[e.tag]||[];t.length>0&&(this.parsedMesh.boundaryElements[e.tag]||(this.parsedMesh.boundaryElements[e.tag]=[]),t.forEach((t=>{const s=t[0],i=t[1];n(`Processing boundary node pair: [${s}, ${i}] for boundary ${e.tag} (${e.name||"unnamed"})`);let r=!1;for(let t=0;t0&&void 0===this.parsedMesh.boundaryElements[0])){const e=[];for(let t=1;t{if("constantTemp"===this.boundaryConditions[s][0]){const o=this.boundaryConditions[s][1];n(`Boundary ${s}: Applying constant temperature of ${o} K (Dirichlet condition)`),this.boundaryElements[s].forEach((([s,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[s][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${s+1}, local node ${i+1})`),e[r]=o;for(let n=0;n{const r=this.nop[s][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${s+1}, local node ${i+1})`),e[r]=o;for(let n=0;n{if("constantTemp"===this.boundaryConditions[s][0]){const o=this.boundaryConditions[s][1];n(`Boundary ${s}: Applying constant temperature of ${o} K (Dirichlet condition)`),this.boundaryElements[s].forEach((([s,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[s][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${s+1}, local node ${i+1})`),e[r]=o;for(let n=0;n{const r=this.nop[s][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${s+1}, local node ${i+1})`),e[r]=o;for(let n=0;n{const t=this.boundaryConditions[e];"convection"===t[0]&&(d[e]=t[1],m[e]=t[2])})),"1D"===this.meshDimension?Object.keys(this.boundaryConditions).forEach((s=>{if("convection"===this.boundaryConditions[s][0]){const o=d[s],i=m[s];n(`Boundary ${s}: Applying convection with heat transfer coefficient h=${o} W/(m²·K) and external temperature T∞=${i} K`),this.boundaryElements[s].forEach((([s,r])=>{let a;"linear"===this.elementOrder?a=0===r?0:1:"quadratic"===this.elementOrder&&(a=0===r?0:2);const l=this.nop[s][a]-1;n(` - Applied convection boundary condition to node ${l+1} (element ${s+1}, local node ${a+1})`),e[l]+=-o*i,t[l][l]+=o}))}})):"2D"===this.meshDimension&&Object.keys(this.boundaryConditions).forEach((s=>{if("convection"===this.boundaryConditions[s][0]){const h=d[s],u=m[s];n(`Boundary ${s}: Applying convection with heat transfer coefficient h=${h} W/(m²·K) and external temperature T∞=${u} K`),this.boundaryElements[s].forEach((([s,d])=>{if("linear"===this.elementOrder){let m,c,f,p,g;0===d?(m=o[0],c=0,f=0,p=3,g=2):1===d?(m=0,c=o[0],f=0,p=2,g=1):2===d?(m=o[0],c=1,f=1,p=4,g=2):3===d&&(m=1,c=o[0],f=2,p=4,g=1);let y=l.getBasisFunctions(m,c),b=y.basisFunction,E=y.basisFunctionDerivKsi,$=y.basisFunctionDerivEta,M=0,v=0,C=0,w=0;const x=this.nop[s].length;for(let e=0;e100){s(`Solution not converged. Error norm: ${l}`);break}c++}return{solutionVector:h,converged:d,iterations:c,jacobianMatrix:m,residualVector:f}}class a{constructor({meshDimension:e,elementOrder:t}){this.meshDimension=e,this.elementOrder=t}getBasisFunctions(e,t=null){let n=[],o=[],i=[];if("1D"===this.meshDimension)"linear"===this.elementOrder?(n[0]=1-e,n[1]=e,o[0]=-1,o[1]=1):"quadratic"===this.elementOrder&&(n[0]=1-3*e+2*e**2,n[1]=4*e-4*e**2,n[2]=2*e**2-e,o[0]=4*e-3,o[1]=4-8*e,o[2]=4*e-1);else if("2D"===this.meshDimension){if(null===t)return void s("Eta coordinate is required for 2D elements");if("linear"===this.elementOrder){function r(e){return 1-e}n[0]=r(e)*r(t),n[1]=r(e)*t,n[2]=e*r(t),n[3]=e*t,o[0]=-1*r(t),o[1]=-1*t,o[2]=1*r(t),o[3]=1*t,i[0]=-1*r(e),i[1]=1*r(e),i[2]=-1*e,i[3]=1*e}else if("quadratic"===this.elementOrder){function a(e){return 2*e**2-3*e+1}function l(e){return-4*e**2+4*e}function d(e){return 2*e**2-e}function c(e){return 4*e-3}function u(e){return-8*e+4}function h(e){return 4*e-1}n[0]=a(e)*a(t),n[1]=a(e)*l(t),n[2]=a(e)*d(t),n[3]=l(e)*a(t),n[4]=l(e)*l(t),n[5]=l(e)*d(t),n[6]=d(e)*a(t),n[7]=d(e)*l(t),n[8]=d(e)*d(t),o[0]=c(e)*a(t),o[1]=c(e)*l(t),o[2]=c(e)*d(t),o[3]=u(e)*a(t),o[4]=u(e)*l(t),o[5]=u(e)*d(t),o[6]=h(e)*a(t),o[7]=h(e)*l(t),o[8]=h(e)*d(t),i[0]=a(e)*c(t),i[1]=a(e)*u(t),i[2]=a(e)*h(t),i[3]=l(e)*c(t),i[4]=l(e)*u(t),i[5]=l(e)*h(t),i[6]=d(e)*c(t),i[7]=d(e)*u(t),i[8]=d(e)*h(t)}}return{basisFunction:n,basisFunctionDerivKsi:o,basisFunctionDerivEta:i}}}class l{constructor({numElementsX:e=null,maxX:t=null,numElementsY:n=null,maxY:s=null,meshDimension:i=null,elementOrder:r="linear",parsedMesh:a=null}){this.numElementsX=e,this.numElementsY=n,this.maxX=t,this.maxY=s,this.meshDimension=i,this.elementOrder=r,this.parsedMesh=a,this.boundaryElementsProcessed=!1,this.parsedMesh&&(o("Using pre-parsed mesh from gmshReader data for mesh generation."),this.parseMeshFromGmsh())}parseMeshFromGmsh(){if(this.parsedMesh.nodalNumbering||s("No valid nodal numbering found in the parsed mesh."),"object"==typeof this.parsedMesh.nodalNumbering&&!Array.isArray(this.parsedMesh.nodalNumbering)){const e=this.parsedMesh.nodalNumbering.quadElements||[];if(this.parsedMesh.nodalNumbering.triangleElements,n("Initial parsed mesh nodal numbering from GMSH format: "+JSON.stringify(this.parsedMesh.nodalNumbering)),this.parsedMesh.elementTypes[3]||this.parsedMesh.elementTypes[10]){const t=[];for(let n=0;n0&&void 0===this.parsedMesh.boundaryElements[0]){const e=[];for(let t=1;t{if(1===e.dimension){const t=this.parsedMesh.boundaryNodePairs[e.tag]||[];t.length>0&&(this.parsedMesh.boundaryElements[e.tag]||(this.parsedMesh.boundaryElements[e.tag]=[]),t.forEach((t=>{const o=t[0],i=t[1];n(`Processing boundary node pair: [${o}, ${i}] for boundary ${e.tag} (${e.name||"unnamed"})`);let r=!1;for(let t=0;t0&&void 0===this.parsedMesh.boundaryElements[0])){const e=[];for(let t=1;t{if("constantValue"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant value of ${s} (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantValue"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant value of ${s} (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantTemp"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant temperature of ${s} K (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantTemp"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant temperature of ${s} K (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const t=this.boundaryConditions[e];"convection"===t[0]&&(d[e]=t[1],c[e]=t[2])})),"1D"===this.meshDimension?Object.keys(this.boundaryConditions).forEach((o=>{if("convection"===this.boundaryConditions[o][0]){const s=d[o],i=c[o];n(`Boundary ${o}: Applying convection with heat transfer coefficient h=${s} W/(m²·K) and external temperature T∞=${i} K`),this.boundaryElements[o].forEach((([o,r])=>{let a;"linear"===this.elementOrder?a=0===r?0:1:"quadratic"===this.elementOrder&&(a=0===r?0:2);const l=this.nop[o][a]-1;n(` - Applied convection boundary condition to node ${l+1} (element ${o+1}, local node ${a+1})`),e[l]+=-s*i,t[l][l]+=s}))}})):"2D"===this.meshDimension&&Object.keys(this.boundaryConditions).forEach((o=>{if("convection"===this.boundaryConditions[o][0]){const u=d[o],h=c[o];n(`Boundary ${o}: Applying convection with heat transfer coefficient h=${u} W/(m²·K) and external temperature T∞=${h} K`),this.boundaryElements[o].forEach((([o,d])=>{if("linear"===this.elementOrder){let c,m,f,p,y;0===d?(c=s[0],m=0,f=0,p=3,y=2):1===d?(c=0,m=s[0],f=0,p=2,y=1):2===d?(c=s[0],m=1,f=1,p=4,y=2):3===d&&(c=1,m=s[0],f=2,p=4,y=1);let g=l.getBasisFunctions(c,m),b=g.basisFunction,E=g.basisFunctionDerivKsi,v=g.basisFunctionDerivEta,M=0,$=0,x=0,C=0;const F=this.nop[o].length;for(let e=0;e{if("constantTemp"===t[e][0]){const n=t[e][1];switch(e){case"0":for(let e=0;e<$.nnx;e++){const t=e*$.nny;$.ncod[t]=1,$.bc[t]=n}break;case"1":for(let e=0;e<$.nny;e++)$.ncod[e]=1,$.bc[e]=n;break;case"2":for(let e=0;e<$.nnx;e++){const t=e*$.nny+($.nny-1);$.ncod[t]=1,$.bc[t]=n}break;case"3":for(let e=0;e<$.nny;e++){const t=($.nnx-1)*$.nny+e;$.ncod[t]=1,$.bc[t]=n}}}}));for(let e=0;e<$.ne;e++)$.ntop[e]=0,$.nlat[e]=0;for(let e=0;e<$.np;e++)$.r1[e]=0;C.npt=$.np,C.iwr1=0,C.ntra=1,C.det=1;for(let e=0;e<$.ne;e++)C.nbn[e]=9;!function(){let e,t=Array(9).fill(0),o=Array(9).fill(0),i=Array(M).fill(0),r=Array(M).fill(0),a=Array(M).fill(0),l=Array(M).fill(0),d=Array(M).fill(0),c=Array(M).fill().map((()=>Array(M).fill(0))),u=Array(v).fill(0),h=Array(v).fill(0),m=Array(v).fill(0),f=1;C.iwr1++;let p=1,y=1;F.nell=0;for(let e=0;eM||g>M)return void s("Error: nmax-nsum not large enough");for(let e=0;e0)for(let e=0;ey||F.nell<$.ne){if(0===x)return void s("Error: no more rows fully summed");let t=r[0],o=a[0],l=c[t-1][o-1];if(Math.abs(l)<1e-4){l=0;for(let e=0;eMath.abs(l)&&(l=i,o=n,t=s)}}}let m=Math.abs(i[t-1]);e=Math.abs(A.lhed[o-1]);let y=m+e+u[m-1]+h[e-1];C.det=C.det*l*(-1)**y/Math.abs(l);for(let t=0;t=m&&u[t]--,t>=e&&h[t]--;if(Math.abs(l)<1e-10&&s(`Warning: matrix singular or ill-conditioned, nell=${F.nell}, kro=${m}, lco=${e}, pivot=${l}`),0===l)return;for(let e=0;e1)for(let e=0;e1&&0!==n)for(let t=0;t1)for(let t=0;t1||F.nell<$.ne)continue;if(e=Math.abs(A.lhed[0]),t=1,l=c[0][0],m=Math.abs(i[0]),o=1,y=m+e+u[m-1]+h[e-1],C.det=C.det*l*(-1)**y/Math.abs(l),A.qq[0]=1,Math.abs(l)<1e-10&&s(`Warning: matrix singular or ill-conditioned, nell=${F.nell}, kro=${m}, lco=${e}, pivot=${l}`),0===l)return;$.r1[m-1]=$.r1[m-1]/l,A.ecv[f-1]=A.qq[0],f++,A.ecv[f-1]=A.lhed[0],f++,A.ecv[f-1]=m,A.ecv[f]=g,A.ecv[f+1]=o,A.ecv[f+2]=l,f+=4,A.ecpiv[p-1]=d[0],p++,A.ecpiv[p-1]=i[0],p++,A.ecpiv[p-1]=t,p++,C.ice1=f,1===C.iwr1&&n(`total ecs transfer in matrix reduction=${f}`),N(f);break}}}();for(let e=0;e<$.np;e++)$.u[e]=C.sk[e];for(let e=0;e<$.np;e++)n(`${$.xpt[e].toExponential(5)} ${$.ypt[e].toExponential(5)} ${$.u[e].toExponential(5)}`)}(e,t),{solutionVector:$.u.slice(0,$.np),nodesCoordinates:{nodesXCoordinates:$.xpt.slice(0,$.np),nodesYCoordinates:$.ypt.slice(0,$.np)}}}const E=1600,v=6724,M=2e3,$={nex:0,ney:0,nnx:0,nny:0,ne:0,np:0,xorigin:0,yorigin:0,xlast:0,ylast:0,deltax:0,deltay:0,nop:Array(E).fill().map((()=>Array(9).fill(0))),xpt:Array(v).fill(0),ypt:Array(v).fill(0),ncod:Array(v).fill(0),bc:Array(v).fill(0),r1:Array(v).fill(0),u:Array(v).fill(0),ntop:Array(E).fill(0),nlat:Array(E).fill(0)},x={w:[.27777777777778,.444444444444,.27777777777778],gp:[.1127016654,.5,.8872983346]},C={iwr1:0,npt:0,ntra:0,nbn:Array(E).fill(0),det:1,sk:Array(M*M).fill(0),ice1:0},F={estifm:Array(9).fill().map((()=>Array(9).fill(0))),nell:0},A={ecv:Array(2e6).fill(0),lhed:Array(M).fill(0),qq:Array(M).fill(0),ecpiv:Array(2e6).fill(0)},w=new a({meshDimension:"2D",elementOrder:"quadratic"});function D(){const e=F.nell-1,{estifm:t,localLoad:n,ngl:o}=function({elementIndex:e,nop:t,xCoordinates:n,yCoordinates:o,basisFunctions:s,gaussPoints:i,gaussWeights:r,ntopFlag:a=!1,nlatFlag:l=!1,convectionTop:d={active:!1,coeff:0,extTemp:0}}){const c=Array(9).fill().map((()=>Array(9).fill(0))),u=Array(9).fill(0),h=Array(9);for(let n=0;n<9;n++)h[n]=Math.abs(t[e][n]);for(let e=0;ee-1)),{detJacobian:m,basisFunctionDerivX:p,basisFunctionDerivY:y}=f({basisFunction:a,basisFunctionDerivKsi:l,basisFunctionDerivEta:d,nodesXCoordinates:n,nodesYCoordinates:o,localToGlobalMap:u,numNodes:9});for(let n=0;n<9;n++)for(let o=0;o<9;o++)c[n][o]-=r[e]*r[t]*m*(p[n]*p[o]+y[n]*y[o])}if(a&&d.active){const a=d.coeff,l=d.extTemp;for(let d=0;d0)continue;let r=0;A.qq[s-1]=0;for(let e=0;e"object"==typeof e&&null!==e||"function"==typeof e,M=new Map([["proxy",{canHandle:e=>$(e)&&e[p],serialize(e){const{port1:t,port2:n}=new MessageChannel;return v(e,t),[n,[n]]},deserialize:e=>(e.start(),w(e))}],["throw",{canHandle:e=>$(e)&&E in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function v(e,t=globalThis,n=["*"]){t.addEventListener("message",(function s(o){if(!o||!o.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,o.origin))return void console.warn(`Invalid origin '${o.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},o.data),l=(o.data.argumentList||[]).map(k);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=k(o.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[p]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;v(e,n),d=function(e,t){return F.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[E]:0}}Promise.resolve(d).catch((e=>({value:e,[E]:0}))).then((n=>{const[o,a]=X(n);t.postMessage(Object.assign(Object.assign({},o),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",s),C(t),b in e&&"function"==typeof e[b]&&e[b]())})).catch((e=>{const[n,s]=X({value:new TypeError("Unserializable return value"),[E]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),s)}))})),t.start&&t.start()}function C(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function w(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const s=n.get(t.id);if(s)try{s(t)}finally{n.delete(t.id)}})),D(e,n,[],t)}function x(e){if(e)throw new Error("Proxy has been released and is not useable")}function S(e){return T(e,new Map,{type:"RELEASE"}).then((()=>{C(e)}))}const N=new WeakMap,O="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(N.get(e)||0)-1;N.set(e,t),0===t&&S(e)}));function D(e,t,n=[],s=function(){}){let o=!1;const i=new Proxy(s,{get(s,r){if(x(o),r===y)return()=>{!function(e){O&&O.unregister(e)}(i),S(e),t.clear(),o=!0};if("then"===r){if(0===n.length)return{then:()=>i};const s=T(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(k);return s.then.bind(s)}return D(e,t,[...n,r])},set(s,i,r){x(o);const[a,l]=X(r);return T(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(k)},apply(s,i,r){x(o);const a=n[n.length-1];if(a===g)return T(e,t,{type:"ENDPOINT"}).then(k);if("bind"===a)return D(e,t,n.slice(0,-1));const[l,d]=A(r);return T(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(k)},construct(s,i){x(o);const[r,a]=A(i);return T(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(k)}});return function(e,t){const n=(N.get(t)||0)+1;N.set(t,n),O&&O.register(e,t,e)}(i,e),i}function A(e){const t=e.map(X);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const F=new WeakMap;function X(e){for(const[t,n]of M)if(n.canHandle(e)){const[s,o]=n.serialize(e);return[{type:"HANDLER",name:t,value:s},o]}return[{type:"RAW",value:e},F.get(e)||[]]}function k(e){switch(e.type){case"HANDLER":return M.get(e.name).deserialize(e.value);case"RAW":return e.value}}function T(e,t,n,s){return new Promise((o=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,o),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),s)}))}exports.FEAScriptModel=class{constructor(){this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",s("FEAScriptModel instance created")}setSolverConfig(e){this.solverConfig=e,n(`Solver config set to: ${e}`)}setMeshConfig(e){this.meshConfig=e,n(`Mesh config set with dimensions: ${e.meshDimension}`)}addBoundaryCondition(e,t){this.boundaryConditions[e]=t,n(`Boundary condition added for boundary: ${e}, type: ${t[0]}`)}setSolverMethod(e){this.solverMethod=e,n(`Solver method set to: ${e}`)}solve(){if(!this.solverConfig||!this.meshConfig||!this.boundaryConditions){const e="Solver config, mesh config, and boundary conditions must be set before solving.";throw console.error(e),new Error(e)}let e=[],t=[],a=[],d=[],p={};if(s("Beginning solving process..."),console.time("totalSolvingTime"),"solidHeatTransferScript"===this.solverConfig){s(`Using solver: ${this.solverConfig}`),({jacobianMatrix:e,residualVector:t,nodesCoordinates:p}=function(e,t){s("Starting solid heat transfer matrix assembly...");const{meshDimension:i,numElementsX:r,numElementsY:a,maxX:d,maxY:c,elementOrder:p,parsedMesh:g}=e;let y;n("Generating mesh..."),"1D"===i?y=new m({numElementsX:r,maxX:d,elementOrder:p,parsedMesh:g}):"2D"===i?y=new h({numElementsX:r,maxX:d,numElementsY:a,maxY:c,elementOrder:p,parsedMesh:g}):o("Mesh dimension must be either '1D' or '2D'.");const b=y.boundaryElementsProcessed?y.parsedMesh:y.generateMesh();let E,$,M=b.nodesXCoordinates,v=b.nodesYCoordinates,C=b.totalNodesX,w=b.totalNodesY,x=b.nodalNumbering,S=b.boundaryElements;null!=g?(E=x.length,$=M.length,n(`Using parsed mesh with ${E} elements and ${$} nodes`)):(E=r*("2D"===i?a:1),$=C*("2D"===i?w:1),n(`Using mesh generated from geometry with ${E} elements and ${$} nodes`));let N,O,D,A,F,X,k,T=[],P=[],Y=[],R=[],W=[],I=[],B=[],j=[],q=[],V=[];for(let e=0;e<$;e++){q[e]=0,V.push([]);for(let t=0;t<$;t++)V[e][t]=0}const L=new l({meshDimension:i,elementOrder:p});let G=new u({meshDimension:i,elementOrder:p}).getGaussPointsAndWeights();P=G.gaussPoints,Y=G.gaussWeights;const U=x[0].length;for(let e=0;e0&&(o.initialSolution=[...a]);const s=r(c,o,100,1e-4);e=s.jacobianMatrix,t=s.residualVector,p=s.nodesCoordinates,a=s.solutionVector,n+=.2}}return console.timeEnd("totalSolvingTime"),s("Solving process completed"),{solutionVector:a,nodesCoordinates:p}}},exports.FEAScriptWorker=class{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js","undefined"==typeof document?new(require("url").URL)("file:"+__filename).href:document.currentScript&&"SCRIPT"===document.currentScript.tagName.toUpperCase()&&document.currentScript.src||new URL("feascript.cjs.js",document.baseURI).href),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=w(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const s=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(s,1e3)};s()}))}async setSolverConfig(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),s("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),s(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),s("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return s(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}},exports.VERSION="0.1.3",exports.importGmshQuadTri=async e=>{let t={nodesXCoordinates:[],nodesYCoordinates:[],nodalNumbering:{quadElements:[],triangleElements:[]},boundaryElements:[],boundaryConditions:[],boundaryNodePairs:{},gmshV:0,ascii:!1,fltBytes:"8",totalNodesX:0,totalNodesY:0,physicalPropMap:[],elementTypes:{}},s=(await e.text()).split("\n").map((e=>e.trim())).filter((e=>""!==e&&" "!==e)),o="",i=0,r=0,a=0,l=0,d={numNodes:0},m=0,h=[],u=0,c=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},g=0,y={};for(;i""!==e));if("meshFormat"===o)t.gmshV=parseFloat(n[0]),t.ascii="0"===n[1],t.fltBytes=n[2];else if("physicalNames"===o){if(n.length>=3){if(!/^\d+$/.test(n[0])){i++;continue}const e=parseInt(n[0],10),s=parseInt(n[1],10);let o=n.slice(2).join(" ");o=o.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:s,dimension:e,name:o})}}else if("nodes"===o){if(0===r){r=parseInt(n[0],10),a=parseInt(n[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;y[n]||(y[n]=[]),y[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);g++,g===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=y[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),n(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t},exports.logSystem=function(e){"basic"!==e&&"debug"!==e?(console.log("%c[WARN] Invalid log level: "+e+". Using basic instead.","color: #FFC107; font-weight: bold;"),t="basic"):(t=e,s(`Log level set to: ${e}`))},exports.plotSolution=function(e,t,n,s,o,i,r="structured"){const{nodesXCoordinates:a,nodesYCoordinates:l}=t;if("1D"===s&&"line"===o){let t;t=e.length>0&&Array.isArray(e[0])?e.map((e=>e[0])):e;let s=Array.from(a),o={x:s,y:t,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},r=Math.min(window.innerWidth,700),l=Math.max(...s),d=r/l,m={title:`line plot - ${n}`,width:Math.max(d*l,400),height:350,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:70,r:40,t:50,b:50}};Plotly.newPlot(i,[o],m,{responsive:!0})}else if("2D"===s&&"contour"===o){const t="structured"===r,s=new Set(a).size,d=new Set(l).size;let m;m=Array.isArray(e[0])?e.map((e=>e[0])):e;let h=Math.min(window.innerWidth,700),u=Math.max(...a),c=Math.max(...l)/u,f=Math.min(h,600),p={title:`${o} plot - ${n}`,width:f,height:f*c*.8,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"};if(t){const t=s,n=d;math.reshape(Array.from(a),[t,n]);let o=math.reshape(Array.from(l),[t,n]),r=math.reshape(Array.from(e),[t,n]),m=math.transpose(r),h=[];for(let e=0;e"object"==typeof e&&null!==e||"function"==typeof e,Y=new Map([["proxy",{canHandle:e=>q(e)&&e[S],serialize(e){const{port1:t,port2:n}=new MessageChannel;return P(e,t),[n,[n]]},deserialize:e=>(e.start(),W(e))}],["throw",{canHandle:e=>q(e)&&T in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function P(e,t=globalThis,n=["*"]){t.addEventListener("message",(function o(s){if(!s||!s.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,s.origin))return void console.warn(`Invalid origin '${s.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},s.data),l=(s.data.argumentList||[]).map(U);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=U(s.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[S]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;P(e,n),d=function(e,t){return K.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[T]:0}}Promise.resolve(d).catch((e=>({value:e,[T]:0}))).then((n=>{const[s,a]=J(n);t.postMessage(Object.assign(Object.assign({},s),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",o),R(t),k in e&&"function"==typeof e[k]&&e[k]())})).catch((e=>{const[n,o]=J({value:new TypeError("Unserializable return value"),[T]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),o)}))})),t.start&&t.start()}function R(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function W(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const o=n.get(t.id);if(o)try{o(t)}finally{n.delete(t.id)}})),G(e,n,[],t)}function I(e){if(e)throw new Error("Proxy has been released and is not useable")}function j(e){return z(e,new Map,{type:"RELEASE"}).then((()=>{R(e)}))}const B=new WeakMap,V="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(B.get(e)||0)-1;B.set(e,t),0===t&&j(e)}));function G(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(I(s),r===X)return()=>{!function(e){V&&V.unregister(e)}(i),j(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=z(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(U);return o.then.bind(o)}return G(e,t,[...n,r])},set(o,i,r){I(s);const[a,l]=J(r);return z(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(U)},apply(o,i,r){I(s);const a=n[n.length-1];if(a===O)return z(e,t,{type:"ENDPOINT"}).then(U);if("bind"===a)return G(e,t,n.slice(0,-1));const[l,d]=L(r);return z(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(U)},construct(o,i){I(s);const[r,a]=L(i);return z(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(U)}});return function(e,t){const n=(B.get(t)||0)+1;B.set(t,n),V&&V.register(e,t,e)}(i,e),i}function L(e){const t=e.map(J);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const K=new WeakMap;function J(e){for(const[t,n]of Y)if(n.canHandle(e)){const[o,s]=n.serialize(e);return[{type:"HANDLER",name:t,value:o},s]}return[{type:"RAW",value:e},K.get(e)||[]]}function U(e){switch(e.type){case"HANDLER":return Y.get(e.name).deserialize(e.value);case"RAW":return e.value}}function z(e,t,n,o){return new Promise((s=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,s),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),o)}))}exports.FEAScriptModel=class{constructor(){this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",o("FEAScriptModel instance created")}setSolverConfig(e){this.solverConfig=e,n(`Solver config set to: ${e}`)}setMeshConfig(e){this.meshConfig=e,n(`Mesh config set with dimensions: ${e.meshDimension}`)}addBoundaryCondition(e,t){this.boundaryConditions[e]=t,n(`Boundary condition added for boundary: ${e}, type: ${t[0]}`)}setSolverMethod(e){this.solverMethod=e,n(`Solver method set to: ${e}`)}solve(){if(!this.solverConfig||!this.meshConfig||!this.boundaryConditions){const e="Solver config, mesh config, and boundary conditions must be set before solving.";throw console.error(e),new Error(e)}let e=[],t=[],a=[],l=[];o("Preparing mesh...");const u=function(e){const{meshDimension:t,numElementsX:o,numElementsY:i,maxX:r,maxY:a,elementOrder:l,parsedMesh:u}=e;let h;"1D"===t?h=new d({numElementsX:o,maxX:r,elementOrder:l,parsedMesh:u}):"2D"===t?h=new c({numElementsX:o,maxX:r,numElementsY:i,maxY:a,elementOrder:l,parsedMesh:u}):s("Mesh dimension must be either '1D' or '2D'.");const m=h.boundaryElementsProcessed?h.parsedMesh:h.generateMesh();let f,p,y=m.nodesXCoordinates,g=m.nodesYCoordinates,b=m.totalNodesX,E=m.totalNodesY,v=m.nodalNumbering,M=m.boundaryElements;return null!=u?(f=v.length,p=y.length,n(`Using parsed mesh with ${f} elements and ${p} nodes`)):(f=o*("2D"===t?i:1),p=b*("2D"===t?E:1),n(`Using mesh generated from geometry with ${f} elements and ${p} nodes`)),{nodesXCoordinates:y,nodesYCoordinates:g,totalNodesX:b,totalNodesY:E,nop:v,boundaryElements:M,totalElements:f,totalNodes:p,meshDimension:t,elementOrder:l}}(this.meshConfig);o("Mesh preparation completed");const p={nodesXCoordinates:u.nodesXCoordinates,nodesYCoordinates:u.nodesYCoordinates};if(o("Beginning solving process..."),console.time("totalSolvingTime"),"solidHeatTransferScript"===this.solverConfig)if(o(`Using solver: ${this.solverConfig}`),"frontal"===this.solverMethod){o("Using frontal solver method");a=b(this.meshConfig,this.boundaryConditions).solutionVector}else{({jacobianMatrix:e,residualVector:t}=function(e,t){o("Starting solid heat transfer matrix assembly...");const{nodesXCoordinates:s,nodesYCoordinates:i,nop:r,boundaryElements:a,totalElements:l,meshDimension:d,elementOrder:c}=e,u=h(e),{residualVector:p,jacobianMatrix:y,localToGlobalMap:b,basisFunctions:E,gaussPoints:v,gaussWeights:M,numNodes:$}=u;for(let e=0;e0&&(i.initialSolution=[...a]);const o=r(y,i,100,1e-4);e=o.jacobianMatrix,t=o.residualVector,a=o.solutionVector,n+=1/s}}return console.timeEnd("totalSolvingTime"),o("Solving process completed"),{solutionVector:a,nodesCoordinates:p}}},exports.FEAScriptWorker=class{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js","undefined"==typeof document?new(require("url").URL)("file:"+__filename).href:document.currentScript&&"SCRIPT"===document.currentScript.tagName.toUpperCase()&&document.currentScript.src||new URL("feascript.cjs.js",document.baseURI).href),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=W(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const o=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(o,1e3)};o()}))}async setSolverConfig(e){return await this._ensureReady(),o(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),o("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),o(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),o(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),o("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return o(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}},exports.VERSION="0.1.3",exports.importGmshQuadTri=async e=>{let t={nodesXCoordinates:[],nodesYCoordinates:[],nodalNumbering:{quadElements:[],triangleElements:[]},boundaryElements:[],boundaryConditions:[],boundaryNodePairs:{},gmshV:0,ascii:!1,fltBytes:"8",totalNodesX:0,totalNodesY:0,physicalPropMap:[],elementTypes:{}},o=(await e.text()).split("\n").map((e=>e.trim())).filter((e=>""!==e&&" "!==e)),s="",i=0,r=0,a=0,l=0,d={numNodes:0},c=0,u=[],h=0,m=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},y=0,g={};for(;i""!==e));if("meshFormat"===s)t.gmshV=parseFloat(n[0]),t.ascii="0"===n[1],t.fltBytes=n[2];else if("physicalNames"===s){if(n.length>=3){if(!/^\d+$/.test(n[0])){i++;continue}const e=parseInt(n[0],10),o=parseInt(n[1],10);let s=n.slice(2).join(" ");s=s.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:o,dimension:e,name:s})}}else if("nodes"===s){if(0===r){r=parseInt(n[0],10),a=parseInt(n[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;g[n]||(g[n]=[]),g[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);y++,y===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=g[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),n(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t},exports.logSystem=function(e){"basic"!==e&&"debug"!==e?(console.log("%c[WARN] Invalid log level: "+e+". Using basic instead.","color: #FFC107; font-weight: bold;"),t="basic"):(t=e,o(`Log level set to: ${e}`))},exports.plotSolution=function(e,t,n,o,s,i,r="structured"){const{nodesXCoordinates:a,nodesYCoordinates:l}=t;if("1D"===o&&"line"===s){let t;t=e.length>0&&Array.isArray(e[0])?e.map((e=>e[0])):e;let o=Array.from(a),s={x:o,y:t,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},r=Math.min(window.innerWidth,700),l=Math.max(...o),d=r/l,c={title:`line plot - ${n}`,width:Math.max(d*l,400),height:350,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:70,r:40,t:50,b:50}};Plotly.newPlot(i,[s],c,{responsive:!0})}else if("2D"===o&&"contour"===s){const t="structured"===r,o=new Set(a).size,d=new Set(l).size;let c;c=Array.isArray(e[0])?e.map((e=>e[0])):e;let u=Math.min(window.innerWidth,700),h=Math.max(...a),m=Math.max(...l)/h,f=Math.min(u,600),p={title:`${s} plot - ${n}`,width:f,height:f*m*.8,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"};if(t){const t=o,n=d;math.reshape(Array.from(a),[t,n]);let s=math.reshape(Array.from(l),[t,n]),r=math.reshape(Array.from(e),[t,n]),c=math.transpose(r),u=[];for(let e=0;e 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n nodesCoordinates,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Helper function to calculate system size from mesh configuration\n * @param {object} meshConfig - Mesh configuration object\n * @returns {number} Total number of nodes in the system\n */\nexport function calculateSystemSize(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, elementOrder, parsedMesh } = meshConfig;\n\n if (parsedMesh && parsedMesh.nodesXCoordinates) {\n // For parsed meshes (like from GMSH)\n return parsedMesh.nodesXCoordinates.length;\n } else {\n // For geometry-based meshes\n let nodesX,\n nodesY = 1;\n\n if (elementOrder === \"linear\") {\n nodesX = numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = numElementsY + 1;\n } else if (elementOrder === \"quadratic\") {\n nodesX = 2 * numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = 2 * numElementsY + 1;\n }\n\n return nodesX * nodesY;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n debugLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n if (\n this.numElementsX === null ||\n this.maxX === null ||\n this.numElementsY === null ||\n this.maxY === null\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n \n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\n\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the front propagation matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation (ranges from 0 to 1)\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleFrontPropagationMat(\n meshConfig,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n // TODO: The mesh generation step should be moved outside of the assembleFrontPropagationMat function so that not performed in every Newton-Raphson iteration\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n let solutionDerivX; // The x-derivative of the solution\n let solutionDerivY; // The y-derivative of the solution\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n detJacobian = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n detJacobian = ksiDerivX;\n }\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n // 2D front propagation (eikonal) equation\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n solutionDerivX = 0;\n solutionDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x & y-derivatives of basis functions and x & y-derivatives of the solution\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n // The x-derivative of the solution\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n // The y-derivative of the solution\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector - Viscous term: Add diffusion contribution to stabilize the solution\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n // residualVector - Eikonal term: Add the eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix - Viscous term: Add the Jacobian contribution from the diffusion term\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n // jacobianMatrix - Eikonal term: Add the Jacobian contribution from the eikonal equation\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n (detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)\n ) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n }\n\n // Create an instance of GenericBoundaryConditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions (Robin type)\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n let nodesCoordinates = {};\n let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term - Used in frontPropagationScript\n let newtonRaphsonIterations;\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleSolidHeatTransferMat(\n this.meshConfig,\n this.boundaryConditions\n ));\n\n // Solve the assembled linear system\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n\n // Create context object with all necessary properties\n const context = {\n meshConfig: this.meshConfig,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n nodesCoordinates = newtonRaphsonResult.nodesCoordinates;\n solutionVector = newtonRaphsonResult.solutionVector;\n newtonRaphsonIterations = newtonRaphsonResult.iterations;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the solid heat transfer matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n // 2D solid heat transfer\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Create an instance of ThermalBoundaryConditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.3\";","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","debugLog","message","console","log","basicLog","errorLog","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","math","lusolve","jacobiSolverResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiSolver","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","nodesCoordinates","totalNodes","meshConfig","meshDimension","numElementsX","numElementsY","elementOrder","parsedMesh","nodesXCoordinates","nodesX","nodesY","calculateSystemSize","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","GenericBoundaryConditions","constructor","boundaryElements","nop","this","imposeConstantValueBoundaryConditions","Object","keys","forEach","boundaryKey","value","elementIndex","side","nodeIndex","globalNodeIndex","colIndex","BasisFunctions","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","maxX","maxY","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","undefined","fixedBoundaryElements","boundaryNodePairs","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","generate1DNodalNumbering","findBoundaryElements","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","assembleFrontPropagationMat","eikonalViscousTerm","mesh","nodesCoordinatesAndNumbering","totalElements","xCoordinates","yCoordinates","ksiDerivX","etaDerivX","ksiDerivY","etaDerivY","detJacobian","solutionDerivX","solutionDerivY","localToGlobalMap","basisFunctionDerivX","basisFunctionDerivY","basisFunctions","gaussPointsAndWeights","numNodes","localNodeIndex","gaussPointIndex1","basisFunctionsAndDerivatives","gaussPointIndex2","localNodeIndex1","localToGlobalMap1","localNodeIndex2","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","Error","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","map","fromWireValue","returnValue","parent","slice","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","r","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","arr","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","thermalBoundaryConditions","assembleSolidHeatTransferMat","newtonRaphsonResult","worker","feaWorker","isReady","_initWorker","Worker","URL","document","require","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","result","toFixed","getModelInfo","ping","terminate","async","file","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","parseInt","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","level","plotType","plotDivId","meshType","yData","xData","from","lineData","mode","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","l","t","b","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString"],"mappings":"aAeO,SAASA,EAAcC,GAC5B,IAAIC,EAAO,EACX,IAAK,IAAIC,EAAI,EAAGA,EAAIF,EAAOG,OAAQD,IACjCD,GAAQD,EAAOE,GAAKF,EAAOE,GAG7B,OADAD,EAAOG,KAAKC,KAAKJ,GACVA,CACT,wDCXA,IAAIK,EAAkB,QAuBf,SAASC,EAASC,GACC,UAApBF,GACFG,QAAQC,IAAI,aAAeF,EAAS,qCAExC,CAMO,SAASG,EAASH,GACvBC,QAAQC,IAAI,YAAcF,EAAS,qCACrC,CAMO,SAASI,EAASJ,GACvBC,QAAQC,IAAI,aAAeF,EAAS,qCACtC,CC3BO,SAASK,EAAkBC,EAAcC,EAAgBC,EAAgBC,EAAU,CAAA,GACxF,MAAMC,cAAEA,EAAgB,IAAIC,UAAEA,EAAY,MAASF,EAEnD,IAAIG,EAAiB,GACjBC,GAAY,EACZC,EAAa,EAMjB,GAHAX,EAAS,wBAAwBG,QACjCL,QAAQc,KAAK,iBAEQ,YAAjBT,EAEFM,EAAiBI,KAAKC,QAAQV,EAAgBC,QACzC,GAAqB,WAAjBF,EAA2B,CAEpC,MACMY,ECrBH,SAAsBX,EAAgBC,EAAgBW,EAAcV,EAAU,CAAA,GACnF,MAAMC,cAAEA,EAAgB,IAAIC,UAAEA,EAAY,MAASF,EAC7CW,EAAIb,EAAeZ,OACzB,IAAI0B,EAAI,IAAIF,GACRG,EAAO,IAAIC,MAAMH,GAErB,IAAK,IAAII,EAAY,EAAGA,EAAYd,EAAec,IAAa,CAE9D,IAAK,IAAI9B,EAAI,EAAGA,EAAI0B,EAAG1B,IAAK,CAC1B,IAAI+B,EAAM,EAEV,IAAK,IAAIC,EAAI,EAAGA,EAAIN,EAAGM,IACjBA,IAAMhC,IACR+B,GAAOlB,EAAeb,GAAGgC,GAAKL,EAAEK,IAIpCJ,EAAK5B,IAAMc,EAAed,GAAK+B,GAAOlB,EAAeb,GAAGA,EACzD,CAGD,IAAIiC,EAAU,EACd,IAAK,IAAIjC,EAAI,EAAGA,EAAI0B,EAAG1B,IACrBiC,EAAU/B,KAAKgC,IAAID,EAAS/B,KAAKiC,IAAIP,EAAK5B,GAAK2B,EAAE3B,KAOnD,GAHA2B,EAAI,IAAIC,GAGJK,EAAUhB,EACZ,MAAO,CACLC,eAAgBS,EAChBP,WAAYU,EAAY,EACxBX,WAAW,EAGhB,CAGD,MAAO,CACLD,eAAgBS,EAChBP,WAAYJ,EACZG,WAAW,EAEf,CDxB+BiB,CAAavB,EAAgBC,EADnC,IAAIe,MAAMf,EAAeb,QAAQoC,KAAK,GAC2B,CACpFrB,gBACAC,cAIEO,EAAmBL,UACrBd,EAAS,8BAA8BmB,EAAmBJ,yBAE1Df,EAAS,wCAAwCmB,EAAmBJ,yBAGtEF,EAAiBM,EAAmBN,eACpCC,EAAYK,EAAmBL,UAC/BC,EAAaI,EAAmBJ,UACpC,MACIV,EAAS,0BAA0BE,KAMrC,OAHAL,QAAQ+B,QAAQ,iBAChB7B,EAAS,8BAEF,CAAES,iBAAgBC,YAAWC,aACtC,CEzCO,SAASmB,EAAcC,EAAaC,EAASzB,EAAgB,IAAKC,EAAY,MACnF,IAAIyB,EAAY,EACZvB,GAAY,EACZC,EAAa,EACbuB,EAAS,GACTzB,EAAiB,GACjBL,EAAiB,GACjBC,EAAiB,GACjB8B,EAAmB,CAAA,EAGnBC,ECtBC,SAA6BC,GAClC,MAAMC,cAAEA,EAAaC,aAAEA,EAAYC,aAAEA,EAAYC,aAAEA,EAAYC,WAAEA,GAAeL,EAEhF,GAAIK,GAAcA,EAAWC,kBAE3B,OAAOD,EAAWC,kBAAkBnD,OAC/B,CAEL,IAAIoD,EACFC,EAAS,EAUX,MARqB,WAAjBJ,GACFG,EAASL,EAAe,EACF,OAAlBD,IAAwBO,EAASL,EAAe,IAC1B,cAAjBC,IACTG,EAAS,EAAIL,EAAe,EACN,OAAlBD,IAAwBO,EAAS,EAAIL,EAAe,IAGnDI,EAASC,CACjB,CACH,CDCmBC,CAAoBd,EAAQK,YAG7C,IAAK,IAAI9C,EAAI,EAAGA,EAAI6C,EAAY7C,IAC9B2C,EAAO3C,GAAK,EACZkB,EAAelB,GAAK,EAQtB,IAJIyC,EAAQe,iBAAmBf,EAAQe,gBAAgBvD,SAAW4C,IAChE3B,EAAiB,IAAIuB,EAAQe,kBAGxBpC,EAAaJ,IAAkBG,GAAW,CAE/C,IAAK,IAAInB,EAAI,EAAGA,EAAIkB,EAAejB,OAAQD,IACzCkB,EAAelB,GAAKyD,OAAOvC,EAAelB,IAAMyD,OAAOd,EAAO3C,MAI7Da,iBAAgBC,iBAAgB8B,oBAAqBJ,EACtDC,EAAQK,WACRL,EAAQiB,mBACRxC,EACAuB,EAAQkB,wBAaV,GARAhB,EAD2BhC,EAAkB8B,EAAQ7B,aAAcC,EAAgBC,GACvDI,eAG5BwB,EAAY7C,EAAc8C,GAG1BlC,EAAS,4BAA4BW,EAAa,mBAAmBsB,EAAUkB,cAAc,MAEzFlB,GAAazB,EACfE,GAAY,OACP,GAAIuB,EAAY,IAAK,CAC1BhC,EAAS,uCAAuCgC,KAChD,KACD,CAEDtB,GACD,CAED,MAAO,CACLF,iBACAC,YACAC,aACAP,iBACAC,iBACA8B,mBAEJ,CEzEO,MAAMiB,EASX,WAAAC,CAAYJ,EAAoBK,EAAkBC,EAAKjB,EAAeG,GACpEe,KAAKP,mBAAqBA,EAC1BO,KAAKF,iBAAmBA,EACxBE,KAAKD,IAAMA,EACXC,KAAKlB,cAAgBA,EACrBkB,KAAKf,aAAeA,CACrB,CAOD,qCAAAgB,CAAsCpD,EAAgBD,GACpDJ,EAAS,gEACkB,OAAvBwD,KAAKlB,cACPoB,OAAOC,KAAKH,KAAKP,oBAAoBW,SAASC,IAC5C,GAAgD,kBAA5CL,KAAKP,mBAAmBY,GAAa,GAAwB,CAC/D,MAAMC,EAAQN,KAAKP,mBAAmBY,GAAa,GACnDjE,EAAS,YAAYiE,iCAA2CC,2BAChEN,KAAKF,iBAAiBO,GAAaD,SAAQ,EAAEG,EAAcC,MACzD,GAA0B,WAAtBR,KAAKf,aAA2B,EACZ,CACpB,EAAG,CAAC,GACJ,EAAG,CAAC,KAEQuB,GAAMJ,SAASK,IAC3B,MAAMC,EAAkBV,KAAKD,IAAIQ,GAAcE,GAAa,EAC5DrE,EACE,sCAAsCsE,EAAkB,cACtDH,EAAe,iBACDE,EAAY,MAG9B5D,EAAe6D,GAAmBJ,EAElC,IAAK,IAAIK,EAAW,EAAGA,EAAW9D,EAAeb,OAAQ2E,IACvD/D,EAAe8D,GAAiBC,GAAY,EAG9C/D,EAAe8D,GAAiBA,GAAmB,CAAC,GAEpE,MAAmB,GAA0B,cAAtBV,KAAKf,aAA8B,EACtB,CACpB,EAAG,CAAC,GACJ,EAAG,CAAC,KAEQuB,GAAMJ,SAASK,IAC3B,MAAMC,EAAkBV,KAAKD,IAAIQ,GAAcE,GAAa,EAC5DrE,EACE,sCAAsCsE,EAAkB,cACtDH,EAAe,iBACDE,EAAY,MAG9B5D,EAAe6D,GAAmBJ,EAElC,IAAK,IAAIK,EAAW,EAAGA,EAAW9D,EAAeb,OAAQ2E,IACvD/D,EAAe8D,GAAiBC,GAAY,EAG9C/D,EAAe8D,GAAiBA,GAAmB,CAAC,GAEvD,IAEJ,KAE6B,OAAvBV,KAAKlB,eACdoB,OAAOC,KAAKH,KAAKP,oBAAoBW,SAASC,IAC5C,GAAgD,kBAA5CL,KAAKP,mBAAmBY,GAAa,GAAwB,CAC/D,MAAMC,EAAQN,KAAKP,mBAAmBY,GAAa,GACnDjE,EAAS,YAAYiE,iCAA2CC,2BAChEN,KAAKF,iBAAiBO,GAAaD,SAAQ,EAAEG,EAAcC,MACzD,GAA0B,WAAtBR,KAAKf,aAA2B,EACZ,CACpB,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,KAEKuB,GAAMJ,SAASK,IAC3B,MAAMC,EAAkBV,KAAKD,IAAIQ,GAAcE,GAAa,EAC5DrE,EACE,sCAAsCsE,EAAkB,cACtDH,EAAe,iBACDE,EAAY,MAG9B5D,EAAe6D,GAAmBJ,EAElC,IAAK,IAAIK,EAAW,EAAGA,EAAW9D,EAAeb,OAAQ2E,IACvD/D,EAAe8D,GAAiBC,GAAY,EAG9C/D,EAAe8D,GAAiBA,GAAmB,CAAC,GAEpE,MAAmB,GAA0B,cAAtBV,KAAKf,aAA8B,EACtB,CACpB,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,KAEEuB,GAAMJ,SAASK,IAC3B,MAAMC,EAAkBV,KAAKD,IAAIQ,GAAcE,GAAa,EAC5DrE,EACE,sCAAsCsE,EAAkB,cACtDH,EAAe,iBACDE,EAAY,MAG9B5D,EAAe6D,GAAmBJ,EAElC,IAAK,IAAIK,EAAW,EAAGA,EAAW9D,EAAeb,OAAQ2E,IACvD/D,EAAe8D,GAAiBC,GAAY,EAG9C/D,EAAe8D,GAAiBA,GAAmB,CAAC,GAEvD,IAEJ,IAGN,ECxII,MAAME,EAMX,WAAAf,EAAYf,cAAEA,EAAaG,aAAEA,IAC3Be,KAAKlB,cAAgBA,EACrBkB,KAAKf,aAAeA,CACrB,CAWD,iBAAA4B,CAAkBC,EAAKC,EAAM,MAC3B,IAAIC,EAAgB,GAChBC,EAAwB,GACxBC,EAAwB,GAE5B,GAA2B,OAAvBlB,KAAKlB,cACmB,WAAtBkB,KAAKf,cAEP+B,EAAc,GAAK,EAAIF,EACvBE,EAAc,GAAKF,EAGnBG,EAAsB,IAAM,EAC5BA,EAAsB,GAAK,GACI,cAAtBjB,KAAKf,eAEd+B,EAAc,GAAK,EAAI,EAAIF,EAAM,EAAIA,GAAO,EAC5CE,EAAc,GAAK,EAAIF,EAAM,EAAIA,GAAO,EACxCE,EAAc,GAAY,EAAIF,GAAO,EAAjBA,EAGpBG,EAAsB,GAAU,EAAIH,EAAR,EAC5BG,EAAsB,GAAK,EAAI,EAAIH,EACnCG,EAAsB,GAAU,EAAIH,EAAR,QAEzB,GAA2B,OAAvBd,KAAKlB,cAAwB,CACtC,GAAY,OAARiC,EAEF,YADAtE,EAAS,8CAIX,GAA0B,WAAtBuD,KAAKf,aAA2B,CAElC,SAASkC,EAAGC,GACV,OAAO,EAAIA,CACZ,CAYDJ,EAAc,GAAKG,EAAGL,GAAOK,EAAGJ,GAChCC,EAAc,GAAKG,EAAGL,GAAUC,EAChCC,EAAc,GAAQF,EAAOK,EAAGJ,GAChCC,EAAc,GAAQF,EAAUC,EAGhCE,EAAsB,IAbZ,EAayBE,EAAGJ,GACtCE,EAAsB,IAdZ,EAc4BF,EACtCE,EAAsB,GAZb,EAY0BE,EAAGJ,GACtCE,EAAsB,GAbb,EAa6BF,EAGtCG,EAAsB,IAnBZ,EAmBiBC,EAAGL,GAC9BI,EAAsB,GAjBb,EAiBkBC,EAAGL,GAC9BI,EAAsB,IArBZ,EAqBoBJ,EAC9BI,EAAsB,GAnBb,EAmBqBJ,CACtC,MAAa,GAA0B,cAAtBd,KAAKf,aAA8B,CAE5C,SAASkC,EAAGC,GACV,OAAO,EAAIA,GAAK,EAAI,EAAIA,EAAI,CAC7B,CACD,SAASC,EAAGD,GACV,OAAQ,EAAIA,GAAK,EAAI,EAAIA,CAC1B,CACD,SAASE,EAAGF,GACV,OAAO,EAAIA,GAAK,EAAIA,CACrB,CACD,SAASG,EAAIH,GACX,OAAO,EAAIA,EAAI,CAChB,CACD,SAASI,EAAIJ,GACX,OAAQ,EAAIA,EAAI,CACjB,CACD,SAASK,EAAIL,GACX,OAAO,EAAIA,EAAI,CAChB,CAGDJ,EAAc,GAAKG,EAAGL,GAAOK,EAAGJ,GAChCC,EAAc,GAAKG,EAAGL,GAAOO,EAAGN,GAChCC,EAAc,GAAKG,EAAGL,GAAOQ,EAAGP,GAChCC,EAAc,GAAKK,EAAGP,GAAOK,EAAGJ,GAChCC,EAAc,GAAKK,EAAGP,GAAOO,EAAGN,GAChCC,EAAc,GAAKK,EAAGP,GAAOQ,EAAGP,GAChCC,EAAc,GAAKM,EAAGR,GAAOK,EAAGJ,GAChCC,EAAc,GAAKM,EAAGR,GAAOO,EAAGN,GAChCC,EAAc,GAAKM,EAAGR,GAAOQ,EAAGP,GAGhCE,EAAsB,GAAKM,EAAIT,GAAOK,EAAGJ,GACzCE,EAAsB,GAAKM,EAAIT,GAAOO,EAAGN,GACzCE,EAAsB,GAAKM,EAAIT,GAAOQ,EAAGP,GACzCE,EAAsB,GAAKO,EAAIV,GAAOK,EAAGJ,GACzCE,EAAsB,GAAKO,EAAIV,GAAOO,EAAGN,GACzCE,EAAsB,GAAKO,EAAIV,GAAOQ,EAAGP,GACzCE,EAAsB,GAAKQ,EAAIX,GAAOK,EAAGJ,GACzCE,EAAsB,GAAKQ,EAAIX,GAAOO,EAAGN,GACzCE,EAAsB,GAAKQ,EAAIX,GAAOQ,EAAGP,GAGzCG,EAAsB,GAAKC,EAAGL,GAAOS,EAAIR,GACzCG,EAAsB,GAAKC,EAAGL,GAAOU,EAAIT,GACzCG,EAAsB,GAAKC,EAAGL,GAAOW,EAAIV,GACzCG,EAAsB,GAAKG,EAAGP,GAAOS,EAAIR,GACzCG,EAAsB,GAAKG,EAAGP,GAAOU,EAAIT,GACzCG,EAAsB,GAAKG,EAAGP,GAAOW,EAAIV,GACzCG,EAAsB,GAAKI,EAAGR,GAAOS,EAAIR,GACzCG,EAAsB,GAAKI,EAAGR,GAAOU,EAAIT,GACzCG,EAAsB,GAAKI,EAAGR,GAAOW,EAAIV,EAC1C,CACF,CAED,MAAO,CAAEC,gBAAeC,wBAAuBC,wBAChD,EC5II,MAAMQ,EAYX,WAAA7B,EAAYd,aACVA,EAAe,KAAI4C,KACnBA,EAAO,KAAI3C,aACXA,EAAe,KAAI4C,KACnBA,EAAO,KAAI9C,cACXA,EAAgB,KAAIG,aACpBA,EAAe,SAAQC,WACvBA,EAAa,OAEbc,KAAKjB,aAAeA,EACpBiB,KAAKhB,aAAeA,EACpBgB,KAAK2B,KAAOA,EACZ3B,KAAK4B,KAAOA,EACZ5B,KAAKlB,cAAgBA,EACrBkB,KAAKf,aAAeA,EACpBe,KAAKd,WAAaA,EAElBc,KAAK6B,2BAA4B,EAE7B7B,KAAKd,aACP1C,EAAS,mEACTwD,KAAK8B,oBAER,CAKD,iBAAAA,GAKE,GAJK9B,KAAKd,WAAW6C,gBACnBtF,EAAS,sDAIiC,iBAAnCuD,KAAKd,WAAW6C,iBACtBnE,MAAMoE,QAAQhC,KAAKd,WAAW6C,gBAC/B,CAEA,MAAME,EAAejC,KAAKd,WAAW6C,eAAeE,cAAgB,GASpE,GARyBjC,KAAKd,WAAW6C,eAAeG,iBAExD9F,EACE,yDACE+F,KAAKC,UAAUpC,KAAKd,WAAW6C,iBAI/B/B,KAAKd,WAAWmD,aAAa,IAAMrC,KAAKd,WAAWmD,aAAa,IAAK,CAEvE,MAAMC,EAAuB,GAE7B,IAAK,IAAIC,EAAU,EAAGA,EAAUN,EAAajG,OAAQuG,IAAW,CAC9D,MAAMC,EAAYP,EAAaM,GACzBE,EAAiB,IAAI7E,MAAM4E,EAAUxG,QAGlB,IAArBwG,EAAUxG,QAOZyG,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,IACA,IAArBA,EAAUxG,SASnByG,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,IAGhCF,EAAqBI,KAAKD,EAC3B,CAEDzC,KAAKd,WAAW6C,eAAiBO,CAClC,MAAUtC,KAAKd,WAAWmD,aAAa,IACtCjG,EAAS,4FASX,GANAA,EACE,gEACE+F,KAAKC,UAAUpC,KAAKd,WAAW6C,iBAI/B/B,KAAKd,WAAWyD,iBAAmB3C,KAAKd,WAAWY,iBAAkB,CAEvE,GACElC,MAAMoE,QAAQhC,KAAKd,WAAWY,mBAC9BE,KAAKd,WAAWY,iBAAiB9D,OAAS,QACF4G,IAAxC5C,KAAKd,WAAWY,iBAAiB,GACjC,CAEA,MAAM+C,EAAwB,GAC9B,IAAK,IAAI9G,EAAI,EAAGA,EAAIiE,KAAKd,WAAWY,iBAAiB9D,OAAQD,IACvDiE,KAAKd,WAAWY,iBAAiB/D,IACnC8G,EAAsBH,KAAK1C,KAAKd,WAAWY,iBAAiB/D,IAGhEiE,KAAKd,WAAWY,iBAAmB+C,CACpC,CAGD,GAAI7C,KAAKd,WAAW4D,oBAAsB9C,KAAKd,WAAW2C,4BAExD7B,KAAKd,WAAWY,iBAAmB,GAGnCE,KAAKd,WAAWyD,gBAAgBvC,SAAS2C,IAEvC,GAAuB,IAAnBA,EAAKC,UAAiB,CAExB,MAAMF,EAAoB9C,KAAKd,WAAW4D,kBAAkBC,EAAKE,MAAQ,GAErEH,EAAkB9G,OAAS,IAExBgE,KAAKd,WAAWY,iBAAiBiD,EAAKE,OACzCjD,KAAKd,WAAWY,iBAAiBiD,EAAKE,KAAO,IAI/CH,EAAkB1C,SAAS8C,IACzB,MAAMC,EAAQD,EAAU,GAClBE,EAAQF,EAAU,GAExB9G,EACE,mCAAmC+G,MAAUC,mBAAuBL,EAAKE,QACvEF,EAAKM,MAAQ,cAKjB,IAAIC,GAAe,EAGnB,IAAK,IAAIf,EAAU,EAAGA,EAAUvC,KAAKd,WAAW6C,eAAe/F,OAAQuG,IAAW,CAChF,MAAMgB,EAAYvD,KAAKd,WAAW6C,eAAeQ,GAGjD,GAAyB,IAArBgB,EAAUvH,QAEZ,GAAIuH,EAAUC,SAASL,IAAUI,EAAUC,SAASJ,GAAQ,CAE1D,IAAI5C,EAEJ,MAAMiD,EAAaF,EAAUG,QAAQP,GAC/BQ,EAAaJ,EAAUG,QAAQN,GAErChH,EACE,mBAAmBmG,gDAAsDgB,EAAUK,KACjF,UAGJxH,EACE,UAAU+G,iBAAqBM,WAAoBL,iBAAqBO,oBASxD,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBnD,EAAO,EACPpE,EAAS,uCAAuCoE,iBAAoB+B,MAEpD,IAAfkB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBnD,EAAO,EACPpE,EAAS,qCAAqCoE,iBAAoB+B,MAElD,IAAfkB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBnD,EAAO,EACPpE,EAAS,oCAAoCoE,iBAAoB+B,OAEjD,IAAfkB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,KAErBnD,EAAO,EACPpE,EAAS,sCAAsCoE,iBAAoB+B,MAIrEvC,KAAKd,WAAWY,iBAAiBiD,EAAKE,KAAKP,KAAK,CAACH,EAAS/B,IAC1DpE,EACE,8BAA8BmG,MAAY/B,sBAAyBuC,EAAKE,OAE1EK,GAAe,EACf,KACD,OACI,GAAyB,IAArBC,EAAUvH,QAGfuH,EAAUC,SAASL,IAAUI,EAAUC,SAASJ,GAAQ,CAE1D,IAAI5C,EAEJ,MAAMiD,EAAaF,EAAUG,QAAQP,GAC/BQ,EAAaJ,EAAUG,QAAQN,GAErChH,EACE,mBAAmBmG,gDAAsDgB,EAAUK,KACjF,UAGJxH,EACE,UAAU+G,iBAAqBM,WAAoBL,iBAAqBO,oBAYxD,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBnD,EAAO,EACPpE,EAAS,uCAAuCoE,iBAAoB+B,MAEpD,IAAfkB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBnD,EAAO,EACPpE,EAAS,qCAAqCoE,iBAAoB+B,MAElD,IAAfkB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBnD,EAAO,EACPpE,EAAS,oCAAoCoE,iBAAoB+B,OAEjD,IAAfkB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,KAErBnD,EAAO,EACPpE,EAAS,sCAAsCoE,iBAAoB+B,MAIrEvC,KAAKd,WAAWY,iBAAiBiD,EAAKE,KAAKP,KAAK,CAACH,EAAS/B,IAC1DpE,EACE,8BAA8BmG,MAAY/B,sBAAyBuC,EAAKE,OAE1EK,GAAe,EACf,KACD,CAEJ,CAEIA,GACH7G,EACE,oDAAoD0G,SAAaC,iCAEpE,IAGN,KAIHpD,KAAK6B,2BAA4B,EAI/B7B,KAAKd,WAAWY,iBAAiB9D,OAAS,QACF4G,IAAxC5C,KAAKd,WAAWY,iBAAiB,IACjC,CACA,MAAM+C,EAAwB,GAC9B,IAAK,IAAI9G,EAAI,EAAGA,EAAIiE,KAAKd,WAAWY,iBAAiB9D,OAAQD,IACvDiE,KAAKd,WAAWY,iBAAiB/D,IACnC8G,EAAsBH,KAAK1C,KAAKd,WAAWY,iBAAiB/D,IAGhEiE,KAAKd,WAAWY,iBAAmB+C,CACpC,CAEJ,CACF,CAED,OAAO7C,KAAKd,UACb,EAGI,MAAM2E,UAAenC,EAS1B,WAAA7B,EAAYd,aAAEA,EAAe,KAAI4C,KAAEA,EAAO,KAAI1C,aAAEA,EAAe,SAAQC,WAAEA,EAAa,OACpF4E,MAAM,CACJ/E,eACA4C,OACA3C,aAAc,EACd4C,KAAM,EACN9C,cAAe,KACfG,eACAC,eAGwB,OAAtBc,KAAKjB,cAAuC,OAAdiB,KAAK2B,MACrClF,EAAS,wFAEZ,CAED,YAAAsH,GACE,IAAI5E,EAAoB,GAGxB,IAAI6E,EAAatF,EAEjB,GAA0B,WAAtBsB,KAAKf,aAA2B,CAClC+E,EAAchE,KAAKjB,aAAe,EAClCL,GAAUsB,KAAK2B,KALF,GAKmB3B,KAAKjB,aAErCI,EAAkB,GAPL,EAQb,IAAK,IAAIsB,EAAY,EAAGA,EAAYuD,EAAavD,IAC/CtB,EAAkBsB,GAAatB,EAAkBsB,EAAY,GAAK/B,CAE1E,MAAW,GAA0B,cAAtBsB,KAAKf,aAA8B,CAC5C+E,EAAc,EAAIhE,KAAKjB,aAAe,EACtCL,GAAUsB,KAAK2B,KAbF,GAamB3B,KAAKjB,aAErCI,EAAkB,GAfL,EAgBb,IAAK,IAAIsB,EAAY,EAAGA,EAAYuD,EAAavD,IAC/CtB,EAAkBsB,GAAatB,EAAkBsB,EAAY,GAAK/B,EAAS,CAE9E,CAED,MAAMqD,EAAiB/B,KAAKiE,yBAAyBjE,KAAKjB,aAAciF,EAAahE,KAAKf,cAEpFa,EAAmBE,KAAKkE,uBAK9B,OAHA9H,EAAS,iCAAmC+F,KAAKC,UAAUjD,IAGpD,CACLA,oBACA6E,cACAjC,iBACAjC,mBAEH,CAUD,wBAAAmE,CAAyBlF,EAAciF,EAAa/E,GAKlD,IAAIc,EAAM,GAEV,GAAqB,WAAjBd,EAOF,IAAK,IAAIsB,EAAe,EAAGA,EAAexB,EAAcwB,IAAgB,CACtER,EAAIQ,GAAgB,GACpB,IAAK,IAAIE,EAAY,EAAGA,GAAa,EAAGA,IACtCV,EAAIQ,GAAcE,EAAY,GAAKF,EAAeE,CAErD,MACI,GAAqB,cAAjBxB,EAA8B,CAOvC,IAAIkF,EAAgB,EACpB,IAAK,IAAI5D,EAAe,EAAGA,EAAexB,EAAcwB,IAAgB,CACtER,EAAIQ,GAAgB,GACpB,IAAK,IAAIE,EAAY,EAAGA,GAAa,EAAGA,IACtCV,EAAIQ,GAAcE,EAAY,GAAKF,EAAeE,EAAY0D,EAEhEA,GAAiB,CAClB,CACF,CAED,OAAOpE,CACR,CAYD,oBAAAmE,GACE,MAAMpE,EAAmB,GAEzB,IAAK,IAAIsE,EAAY,EAAGA,EADP,EAC6BA,IAC5CtE,EAAiB4C,KAAK,IAWxB,OAPA5C,EAAiB,GAAG4C,KAAK,CAAC,EAAG,IAG7B5C,EAAiB,GAAG4C,KAAK,CAAC1C,KAAKjB,aAAe,EAAG,IAEjD3C,EAAS,yCAA2C+F,KAAKC,UAAUtC,IACnEE,KAAK6B,2BAA4B,EAC1B/B,CACR,EAGI,MAAMuE,UAAe3C,EAW1B,WAAA7B,EAAYd,aACVA,EAAe,KAAI4C,KACnBA,EAAO,KAAI3C,aACXA,EAAe,KAAI4C,KACnBA,EAAO,KAAI3C,aACXA,EAAe,SAAQC,WACvBA,EAAa,OAEb4E,MAAM,CACJ/E,eACA4C,OACA3C,eACA4C,OACA9C,cAAe,KACfG,eACAC,eAIsB,OAAtBc,KAAKjB,cACS,OAAdiB,KAAK2B,MACiB,OAAtB3B,KAAKhB,cACS,OAAdgB,KAAK4B,MAELnF,EACE,6GAGL,CAED,YAAAsH,GACE,IAAI5E,EAAoB,GACpBmF,EAAoB,GAGxB,IAAIN,EAAaO,EAAa7F,EAAQ8F,EAEtC,GAA0B,WAAtBxE,KAAKf,aAA2B,CAClC+E,EAAchE,KAAKjB,aAAe,EAClCwF,EAAcvE,KAAKhB,aAAe,EAClCN,GAAUsB,KAAK2B,KAPF,GAOmB3B,KAAKjB,aACrCyF,GAAUxE,KAAK4B,KAPF,GAOmB5B,KAAKhB,aAErCG,EAAkB,GAVL,EAWbmF,EAAkB,GAVL,EAWb,IAAK,IAAIG,EAAa,EAAGA,EAAaF,EAAaE,IACjDtF,EAAkBsF,GAActF,EAAkB,GAClDmF,EAAkBG,GAAcH,EAAkB,GAAKG,EAAaD,EAEtE,IAAK,IAAIE,EAAa,EAAGA,EAAaV,EAAaU,IAAc,CAC/D,MAAMC,EAAQD,EAAaH,EAC3BpF,EAAkBwF,GAASxF,EAAkB,GAAKuF,EAAahG,EAC/D4F,EAAkBK,GAASL,EAAkB,GAC7C,IAAK,IAAIG,EAAa,EAAGA,EAAaF,EAAaE,IACjDtF,EAAkBwF,EAAQF,GAActF,EAAkBwF,GAC1DL,EAAkBK,EAAQF,GAAcH,EAAkBK,GAASF,EAAaD,CAEnF,CACP,MAAW,GAA0B,cAAtBxE,KAAKf,aAA8B,CAC5C+E,EAAc,EAAIhE,KAAKjB,aAAe,EACtCwF,EAAc,EAAIvE,KAAKhB,aAAe,EACtCN,GAAUsB,KAAK2B,KA5BF,GA4BmB3B,KAAKjB,aACrCyF,GAAUxE,KAAK4B,KA5BF,GA4BmB5B,KAAKhB,aAErCG,EAAkB,GA/BL,EAgCbmF,EAAkB,GA/BL,EAgCb,IAAK,IAAIG,EAAa,EAAGA,EAAaF,EAAaE,IACjDtF,EAAkBsF,GAActF,EAAkB,GAClDmF,EAAkBG,GAAcH,EAAkB,GAAMG,EAAaD,EAAU,EAEjF,IAAK,IAAIE,EAAa,EAAGA,EAAaV,EAAaU,IAAc,CAC/D,MAAMC,EAAQD,EAAaH,EAC3BpF,EAAkBwF,GAASxF,EAAkB,GAAMuF,EAAahG,EAAU,EAC1E4F,EAAkBK,GAASL,EAAkB,GAC7C,IAAK,IAAIG,EAAa,EAAGA,EAAaF,EAAaE,IACjDtF,EAAkBwF,EAAQF,GAActF,EAAkBwF,GAC1DL,EAAkBK,EAAQF,GAAcH,EAAkBK,GAAUF,EAAaD,EAAU,CAE9F,CACF,CAGD,MAAMzC,EAAiB/B,KAAK4E,yBAC1B5E,KAAKjB,aACLiB,KAAKhB,aACLuF,EACAvE,KAAKf,cAIDa,EAAmBE,KAAKkE,uBAM9B,OAJA9H,EAAS,iCAAmC+F,KAAKC,UAAUjD,IAC3D/C,EAAS,iCAAmC+F,KAAKC,UAAUkC,IAGpD,CACLnF,oBACAmF,oBACAN,cACAO,cACAxC,iBACAjC,mBAEH,CAYD,wBAAA8E,CAAyB7F,EAAcC,EAAcuF,EAAatF,GAChE,IAAIsB,EAAe,EACfR,EAAM,GAEV,GAAqB,WAAjBd,EAA2B,CAS7B,IAAI4F,EAAa,EACbV,EAAgB,EACpB,IAAK,IAAI5D,EAAe,EAAGA,EAAexB,EAAeC,EAAcuB,IACrEsE,GAAc,EACd9E,EAAIQ,GAAgB,GACpBR,EAAIQ,GAAc,GAAKA,EAAe4D,EAAgB,EACtDpE,EAAIQ,GAAc,GAAKA,EAAe4D,EACtCpE,EAAIQ,GAAc,GAAKA,EAAe4D,EAAgBnF,EACtDe,EAAIQ,GAAc,GAAKA,EAAe4D,EAAgBnF,EAAe,EACjE6F,IAAe7F,IACjBmF,GAAiB,EACjBU,EAAa,EAGvB,MAAW,GAAqB,cAAjB5F,EAWT,IAAK,IAAI6F,EAAgB,EAAGA,GAAiB/F,EAAc+F,IACzD,IAAK,IAAIC,EAAgB,EAAGA,GAAiB/F,EAAc+F,IAAiB,CAC1EhF,EAAIQ,GAAgB,GACpB,IAAK,IAAIyE,EAAa,EAAGA,GAAc,EAAGA,IAAc,CACtD,IAAIC,EAAa,EAAID,EAAa,EAClCjF,EAAIQ,GAAc0E,EAAa,GAC7BV,GAAe,EAAIO,EAAgBE,EAAa,GAAK,EAAID,EAAgB,EAC3EhF,EAAIQ,GAAc0E,GAAclF,EAAIQ,GAAc0E,EAAa,GAAK,EACpElF,EAAIQ,GAAc0E,EAAa,GAAKlF,EAAIQ,GAAc0E,EAAa,GAAK,CACzE,CACD1E,GAA8B,CAC/B,CAIL,OAAOR,CACR,CAcD,oBAAAmE,GACE,MAAMpE,EAAmB,GAGzB,IAAK,IAAIsE,EAAY,EAAGA,EAFP,EAE6BA,IAC5CtE,EAAiB4C,KAAK,IAMxB,IAAK,IAAIoC,EAAgB,EAAGA,EAAgB9E,KAAKjB,aAAc+F,IAC7D,IAAK,IAAIC,EAAgB,EAAGA,EAAgB/E,KAAKhB,aAAc+F,IAAiB,CAC9E,MAAMxE,EAAeuE,EAAgB9E,KAAKhB,aAAe+F,EAGnC,IAAlBA,GACFjF,EAAiB,GAAG4C,KAAK,CAACnC,EAAc,IAIpB,IAAlBuE,GACFhF,EAAiB,GAAG4C,KAAK,CAACnC,EAAc,IAItCwE,IAAkB/E,KAAKhB,aAAe,GACxCc,EAAiB,GAAG4C,KAAK,CAACnC,EAAc,IAItCuE,IAAkB9E,KAAKjB,aAAe,GACxCe,EAAiB,GAAG4C,KAAK,CAACnC,EAAc,GAE3C,CAKH,OAFAnE,EAAS,yCAA2C+F,KAAKC,UAAUtC,IACnEE,KAAK6B,2BAA4B,EAC1B/B,CACR,EC7sBI,MAAMoF,EAMX,WAAArF,EAAYf,cAAEA,EAAaG,aAAEA,IAC3Be,KAAKlB,cAAgBA,EACrBkB,KAAKf,aAAeA,CACrB,CAQD,wBAAAkG,GACE,IAAIC,EAAc,GACdC,EAAe,GAgBnB,MAd0B,WAAtBrF,KAAKf,cAEPmG,EAAY,GAAK,GACjBC,EAAa,GAAK,GACa,cAAtBrF,KAAKf,eAEdmG,EAAY,IAAM,EAAInJ,KAAKC,KAAK,KAAU,EAC1CkJ,EAAY,GAAK,GACjBA,EAAY,IAAM,EAAInJ,KAAKC,KAAK,KAAU,EAC1CmJ,EAAa,GAAK,EAAI,GACtBA,EAAa,GAAK,EAAI,GACtBA,EAAa,GAAK,EAAI,IAGjB,CAAED,cAAaC,eACvB,ECpBI,SAASC,EACdzG,EACAY,EACAxC,EACAyC,GAEAlD,EAAS,iDAGT,IAAI+I,EAAqB,EAAI7F,EADE,IAE/BlD,EAAS,uBAAuB+I,KAChC/I,EAAS,0BAA0BkD,KAGnC,MAAMZ,cACJA,EAAaC,aACbA,EAAYC,aACZA,EAAY2C,KACZA,EAAIC,KACJA,EAAI3C,aACJA,EAAYC,WACZA,GACEL,EAKJ,IAAI2G,EADJpJ,EAAS,sBAEa,OAAlB0C,EACF0G,EAAO,IAAI3B,EAAO,CAAE9E,eAAc4C,OAAM1C,eAAcC,eAC3B,OAAlBJ,EACT0G,EAAO,IAAInB,EAAO,CAAEtF,eAAc4C,OAAM3C,eAAc4C,OAAM3C,eAAcC,eAE1EzC,EAAS,+CAIX,MAAMgJ,EAA+BD,EAAK3D,0BAA4B2D,EAAKtG,WAAasG,EAAKzB,eAG7F,IAAI5E,EAAoBsG,EAA6BtG,kBACjDmF,EAAoBmB,EAA6BnB,kBACjDN,EAAcyB,EAA6BzB,YAC3CO,EAAckB,EAA6BlB,YAC3CxE,EAAM0F,EAA6B1D,eACnCjC,EAAmB2F,EAA6B3F,iBAMpD,IAAI4F,EAAe9G,EAHEM,SAMnBwG,EAAgB3F,EAAI/D,OACpB4C,EAAaO,EAAkBnD,OAG/BI,EAAS,0BAA0BsJ,kBAA8B9G,aAGjE8G,EAAgB3G,GAAkC,OAAlBD,EAAyBE,EAAe,GACxEJ,EAAaoF,GAAiC,OAAlBlF,EAAyByF,EAAc,GAEnEnI,EAAS,2CAA2CsJ,kBAA8B9G,YAIpF,IAUI+G,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EAlBAC,EAAmB,GACnBhB,EAAc,GACdC,EAAe,GACfrE,EAAgB,GAChBC,EAAwB,GACxBC,EAAwB,GACxBmF,EAAsB,GACtBC,EAAsB,GACtBzJ,EAAiB,GACjBD,EAAiB,GAYrB,IAAK,IAAI6D,EAAY,EAAGA,EAAY7B,EAAY6B,IAAa,CAC3D5D,EAAe4D,GAAa,EAC5B7D,EAAe8F,KAAK,IACpB,IAAK,IAAI/B,EAAW,EAAGA,EAAW/B,EAAY+B,IAC5C/D,EAAe6D,GAAWE,GAAY,CAEzC,CAGD,MAAM4F,EAAiB,IAAI3F,EAAe,CACxC9B,gBACAG,iBAUF,IAAIuH,EANyB,IAAItB,EAAqB,CACpDpG,gBACAG,iBAI+CkG,2BACjDC,EAAcoB,EAAsBpB,YACpCC,EAAemB,EAAsBnB,aAGrC,MAAMoB,EAAW1G,EAAI,GAAG/D,OAGxB,IAAK,IAAIuE,EAAe,EAAGA,EAAemF,EAAenF,IAAgB,CACvE,IAAK,IAAImG,EAAiB,EAAGA,EAAiBD,EAAUC,IAEtDN,EAAiBM,GAAkB3G,EAAIQ,GAAcmG,GAAkB,EAIzE,IAAK,IAAIC,EAAmB,EAAGA,EAAmBvB,EAAYpJ,OAAQ2K,IAEpE,GAAsB,OAAlB7H,EAAwB,CAC1B,IAAI8H,EAA+BL,EAAe1F,kBAAkBuE,EAAYuB,IAChF3F,EAAgB4F,EAA6B5F,cAC7CC,EAAwB2F,EAA6B3F,sBACrD0E,EAAe,EACfE,EAAY,EACZI,EAAc,EAGd,IAAK,IAAIS,EAAiB,EAAGA,EAAiBD,EAAUC,IACtDf,GAAgBxG,EAAkBiH,EAAiBM,IAAmB1F,EAAc0F,GACpFb,GACE1G,EAAkBiH,EAAiBM,IAAmBzF,EAAsByF,GAC9ET,EAAcJ,EAIhB,IAAK,IAAIa,EAAiB,EAAGA,EAAiBD,EAAUC,IACtDL,EAAoBK,GAAkBzF,EAAsByF,GAAkBT,CAgBxF,MAAa,GAAsB,OAAlBnH,EACT,IAAK,IAAI+H,EAAmB,EAAGA,EAAmBzB,EAAYpJ,OAAQ6K,IAAoB,CAExF,IAAID,EAA+BL,EAAe1F,kBAChDuE,EAAYuB,GACZvB,EAAYyB,IAEd7F,EAAgB4F,EAA6B5F,cAC7CC,EAAwB2F,EAA6B3F,sBACrDC,EAAwB0F,EAA6B1F,sBACrDyE,EAAe,EACfC,EAAe,EACfC,EAAY,EACZC,EAAY,EACZC,EAAY,EACZC,EAAY,EACZE,EAAiB,EACjBC,EAAiB,EAGjB,IAAK,IAAIO,EAAiB,EAAGA,EAAiBD,EAAUC,IACtDf,GACExG,EAAkBiH,EAAiBM,IAAmB1F,EAAc0F,GACtEd,GACEtB,EAAkB8B,EAAiBM,IAAmB1F,EAAc0F,GACtEb,GACE1G,EAAkBiH,EAAiBM,IAAmBzF,EAAsByF,GAC9EZ,GACE3G,EAAkBiH,EAAiBM,IAAmBxF,EAAsBwF,GAC9EX,GACEzB,EAAkB8B,EAAiBM,IAAmBzF,EAAsByF,GAC9EV,GACE1B,EAAkB8B,EAAiBM,IAAmBxF,EAAsBwF,GAEhFT,EAAcJ,EAAYG,EAAYF,EAAYC,EAGlD,IAAK,IAAIW,EAAiB,EAAGA,EAAiBD,EAAUC,IAEtDL,EAAoBK,IACjBV,EAAY/E,EAAsByF,GACjCX,EAAY7E,EAAsBwF,IACpCT,EAEFK,EAAoBI,IACjBb,EAAY3E,EAAsBwF,GACjCZ,EAAY7E,EAAsByF,IACpCT,EAEFC,GACEjJ,EAAemJ,EAAiBM,IAAmBL,EAAoBK,GAEzEP,GACElJ,EAAemJ,EAAiBM,IAAmBJ,EAAoBI,GAI3E,IAAK,IAAII,EAAkB,EAAGA,EAAkBL,EAAUK,IAAmB,CAC3E,IAAIC,EAAoBX,EAAiBU,GAEzCjK,EAAekK,IACbxB,EACEF,EAAasB,GACbtB,EAAawB,GACbZ,EACAI,EAAoBS,GACpBZ,EACFX,EACEF,EAAasB,GACbtB,EAAawB,GACbZ,EACAK,EAAoBQ,GACpBX,EAE0B,IAA1BzG,IACF7C,EAAekK,IACbrH,GACC2F,EAAasB,GACZtB,EAAawB,GACbZ,EACAjF,EAAc8F,GACd7K,KAAKC,KAAKgK,GAAkB,EAAIC,GAAkB,GAClDd,EAAasB,GACXtB,EAAawB,GACbZ,EACAjF,EAAc8F,KAEtB,IAAK,IAAIE,EAAkB,EAAGA,EAAkBP,EAAUO,IAAmB,CAC3E,IAAIC,EAAoBb,EAAiBY,GAEzCpK,EAAemK,GAAmBE,KAC/B1B,EACDF,EAAasB,GACbtB,EAAawB,GACbZ,GACCI,EAAoBS,GAAmBT,EAAoBW,GAC1DV,EAAoBQ,GAAmBR,EAAoBU,IAEjC,IAA1BtH,IACF9C,EAAemK,GAAmBE,IAChCvH,IAEGuG,EACCC,EACAlF,EAAc8F,GACdzB,EAAasB,GACbtB,EAAawB,GACf5K,KAAKC,KAAKgK,GAAkB,EAAIC,GAAkB,EAAI,MAEtDE,EAAoBW,GAClBf,EACAE,EACAnF,EAAc8F,GACdzB,EAAasB,GACbtB,EAAawB,GACb5K,KAAKC,KAAKgK,GAAkB,EAAIC,GAAkB,EAAI,MACtDG,EAAoBU,IAE7B,CACF,CACF,CAGN,CAGDxK,EAAS,2CACyB,IAAIoD,EACpCH,EACAK,EACAC,EACAjB,EACAG,GAIwBgB,sCAAsCpD,EAAgBD,GAChFJ,EAAS,8CAGTJ,EAAS,2BACT,IAAK,IAAIL,EAAI,EAAGA,EAAIc,EAAeb,OAAQD,IACzCK,EAAS,QAAQL,MAAMc,EAAed,GAAG4D,cAAc,MAKzD,OAFAnD,EAAS,+CAEF,CACLI,iBACAC,iBACA8B,iBAAkB,CAChBQ,oBACAmF,qBAGN,CCzUO,MAAM4C,EASX,WAAArH,CAAYJ,EAAoBK,EAAkBC,EAAKjB,EAAeG,GACpEe,KAAKP,mBAAqBA,EAC1BO,KAAKF,iBAAmBA,EACxBE,KAAKD,IAAMA,EACXC,KAAKlB,cAAgBA,EACrBkB,KAAKf,aAAeA,CACrB,CAOD,oCAAAkI,CAAqCtK,EAAgBD,GACnDJ,EAAS,sEACkB,OAAvBwD,KAAKlB,cACPoB,OAAOC,KAAKH,KAAKP,oBAAoBW,SAASC,IAC5C,GAAgD,iBAA5CL,KAAKP,mBAAmBY,GAAa,GAAuB,CAC9D,MAAM+G,EAAYpH,KAAKP,mBAAmBY,GAAa,GACvDjE,EACE,YAAYiE,uCAAiD+G,6BAE/DpH,KAAKF,iBAAiBO,GAAaD,SAAQ,EAAEG,EAAcC,MACzD,GAA0B,WAAtBR,KAAKf,aAA2B,EACZ,CACpB,EAAG,CAAC,GACJ,EAAG,CAAC,KAEQuB,GAAMJ,SAASK,IAC3B,MAAMC,EAAkBV,KAAKD,IAAIQ,GAAcE,GAAa,EAC5DrE,EACE,4CAA4CsE,EAAkB,cAC5DH,EAAe,iBACDE,EAAY,MAG9B5D,EAAe6D,GAAmB0G,EAElC,IAAK,IAAIzG,EAAW,EAAGA,EAAW9D,EAAeb,OAAQ2E,IACvD/D,EAAe8D,GAAiBC,GAAY,EAG9C/D,EAAe8D,GAAiBA,GAAmB,CAAC,GAEpE,MAAmB,GAA0B,cAAtBV,KAAKf,aAA8B,EACtB,CACpB,EAAG,CAAC,GACJ,EAAG,CAAC,KAEQuB,GAAMJ,SAASK,IAC3B,MAAMC,EAAkBV,KAAKD,IAAIQ,GAAcE,GAAa,EAC5DrE,EACE,4CAA4CsE,EAAkB,cAC5DH,EAAe,iBACDE,EAAY,MAG9B5D,EAAe6D,GAAmB0G,EAElC,IAAK,IAAIzG,EAAW,EAAGA,EAAW9D,EAAeb,OAAQ2E,IACvD/D,EAAe8D,GAAiBC,GAAY,EAG9C/D,EAAe8D,GAAiBA,GAAmB,CAAC,GAEvD,IAEJ,KAE6B,OAAvBV,KAAKlB,eACdoB,OAAOC,KAAKH,KAAKP,oBAAoBW,SAASC,IAC5C,GAAgD,iBAA5CL,KAAKP,mBAAmBY,GAAa,GAAuB,CAC9D,MAAM+G,EAAYpH,KAAKP,mBAAmBY,GAAa,GACvDjE,EACE,YAAYiE,uCAAiD+G,6BAE/DpH,KAAKF,iBAAiBO,GAAaD,SAAQ,EAAEG,EAAcC,MACzD,GAA0B,WAAtBR,KAAKf,aAA2B,EACZ,CACpB,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,KAEKuB,GAAMJ,SAASK,IAC3B,MAAMC,EAAkBV,KAAKD,IAAIQ,GAAcE,GAAa,EAC5DrE,EACE,4CAA4CsE,EAAkB,cAC5DH,EAAe,iBACDE,EAAY,MAG9B5D,EAAe6D,GAAmB0G,EAElC,IAAK,IAAIzG,EAAW,EAAGA,EAAW9D,EAAeb,OAAQ2E,IACvD/D,EAAe8D,GAAiBC,GAAY,EAG9C/D,EAAe8D,GAAiBA,GAAmB,CAAC,GAEpE,MAAmB,GAA0B,cAAtBV,KAAKf,aAA8B,EACtB,CACpB,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,KAEEuB,GAAMJ,SAASK,IAC3B,MAAMC,EAAkBV,KAAKD,IAAIQ,GAAcE,GAAa,EAC5DrE,EACE,4CAA4CsE,EAAkB,cAC5DH,EAAe,iBACDE,EAAY,MAG9B5D,EAAe6D,GAAmB0G,EAElC,IAAK,IAAIzG,EAAW,EAAGA,EAAW9D,EAAeb,OAAQ2E,IACvD/D,EAAe8D,GAAiBC,GAAY,EAG9C/D,EAAe8D,GAAiBA,GAAmB,CAAC,GAEvD,IAEJ,IAGN,CAYD,kCAAA2G,CACExK,EACAD,EACAwI,EACAC,EACAlG,EACAmF,EACAiC,GAEA/J,EAAS,wDAET,IAAI8K,EAA2B,GAC3BC,EAAoB,GACxBrH,OAAOC,KAAKH,KAAKP,oBAAoBW,SAASoH,IAC5C,MAAMC,EAAoBzH,KAAKP,mBAAmB+H,GACrB,eAAzBC,EAAkB,KACpBH,EAAyBE,GAAOC,EAAkB,GAClDF,EAAkBC,GAAOC,EAAkB,GAC5C,IAGwB,OAAvBzH,KAAKlB,cACPoB,OAAOC,KAAKH,KAAKP,oBAAoBW,SAASC,IAC5C,GAAgD,eAA5CL,KAAKP,mBAAmBY,GAAa,GAAqB,CAC5D,MAAMqH,EAAkBJ,EAAyBjH,GAC3CsH,EAAUJ,EAAkBlH,GAClCjE,EACE,YAAYiE,2DAAqEqH,0CAAwDC,OAE3I3H,KAAKF,iBAAiBO,GAAaD,SAAQ,EAAEG,EAAcC,MACzD,IAAIC,EACsB,WAAtBT,KAAKf,aAGLwB,EAFW,IAATD,EAEU,EAGA,EAEiB,cAAtBR,KAAKf,eAGZwB,EAFW,IAATD,EAEU,EAGA,GAIhB,MAAME,EAAkBV,KAAKD,IAAIQ,GAAcE,GAAa,EAC5DrE,EACE,qDAAqDsE,EAAkB,cACrEH,EAAe,iBACDE,EAAY,MAE9B5D,EAAe6D,KAAqBgH,EAAkBC,EACtD/K,EAAe8D,GAAiBA,IAAoBgH,CAAe,GAEtE,KAE6B,OAAvB1H,KAAKlB,eACdoB,OAAOC,KAAKH,KAAKP,oBAAoBW,SAASC,IAC5C,GAAgD,eAA5CL,KAAKP,mBAAmBY,GAAa,GAAqB,CAC5D,MAAMqH,EAAkBJ,EAAyBjH,GAC3CsH,EAAUJ,EAAkBlH,GAClCjE,EACE,YAAYiE,2DAAqEqH,0CAAwDC,OAE3I3H,KAAKF,iBAAiBO,GAAaD,SAAQ,EAAEG,EAAcC,MACzD,GAA0B,WAAtBR,KAAKf,aAA2B,CAClC,IAAI2I,EAAaC,EAAaC,EAAgBC,EAAeC,EAChD,IAATxH,GAEFoH,EAAcxC,EAAY,GAC1ByC,EAAc,EACdC,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATxH,GAEToH,EAAc,EACdC,EAAczC,EAAY,GAC1B0C,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATxH,GAEToH,EAAcxC,EAAY,GAC1ByC,EAAc,EACdC,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATxH,IAEToH,EAAc,EACdC,EAAczC,EAAY,GAC1B0C,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GAGlB,IAAIpB,EAA+BL,EAAe1F,kBAAkB+G,EAAaC,GAC7E7G,EAAgB4F,EAA6B5F,cAC7CC,EAAwB2F,EAA6B3F,sBACrDC,EAAwB0F,EAA6B1F,sBAErD2E,EAAY,EACZE,EAAY,EACZD,EAAY,EACZE,EAAY,EAChB,MAAMS,EAAWzG,KAAKD,IAAIQ,GAAcvE,OACxC,IAAK,IAAIyE,EAAY,EAAGA,EAAYgG,EAAUhG,IAAa,CACzD,MAAMC,EAAkBV,KAAKD,IAAIQ,GAAcE,GAAa,EAG/C,IAATD,GAAuB,IAATA,GAChBqF,GAAa1G,EAAkBuB,GAAmBO,EAAsBR,GACxEsF,GAAazB,EAAkB5D,GAAmBO,EAAsBR,IAGxD,IAATD,GAAuB,IAATA,IACrBsF,GAAa3G,EAAkBuB,GAAmBQ,EAAsBT,GACxEuF,GAAa1B,EAAkB5D,GAAmBQ,EAAsBT,GAE3E,CAGD,IAAIwH,EAEFA,EADW,IAATzH,GAAuB,IAATA,EACMvE,KAAKC,KAAK2J,GAAa,EAAIE,GAAa,GAExC9J,KAAKC,KAAK4J,GAAa,EAAIE,GAAa,GAGhE,IACE,IAAIU,EAAiBoB,EACrBpB,EAAiBqB,EACjBrB,GAAkBsB,EAClB,CACA,IAAItH,EAAkBV,KAAKD,IAAIQ,GAAcmG,GAAkB,EAC/DtK,EACE,qDAAqDsE,EAAkB,cACrEH,EAAe,iBACDmG,EAAiB,MAInC7J,EAAe6D,KACZ2E,EAAa,GACd4C,EACAjH,EAAc0F,GACdgB,EACAC,EAEF,IACE,IAAIX,EAAkBc,EACtBd,EAAkBe,EAClBf,GAAmBgB,EACnB,CACA,IAAIE,EAAmBlI,KAAKD,IAAIQ,GAAcyG,GAAmB,EACjEpK,EAAe8D,GAAiBwH,KAC7B7C,EAAa,GACd4C,EACAjH,EAAc0F,GACd1F,EAAcgG,GACdU,CACH,CACF,CACf,MAAmB,GAA0B,cAAtB1H,KAAKf,aACd,IAAK,IAAIkJ,EAAkB,EAAGA,EAAkB,EAAGA,IAAmB,CACpE,IAAIP,EAAaC,EAAaC,EAAgBC,EAAeC,EAChD,IAATxH,GAEFoH,EAAcxC,EAAY+C,GAC1BN,EAAc,EACdC,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATxH,GAEToH,EAAc,EACdC,EAAczC,EAAY+C,GAC1BL,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATxH,GAEToH,EAAcxC,EAAY+C,GAC1BN,EAAc,EACdC,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATxH,IAEToH,EAAc,EACdC,EAAczC,EAAY+C,GAC1BL,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GAElB,IAAIpB,EAA+BL,EAAe1F,kBAAkB+G,EAAaC,GAC7E7G,EAAgB4F,EAA6B5F,cAC7CC,EAAwB2F,EAA6B3F,sBACrDC,EAAwB0F,EAA6B1F,sBAErD2E,EAAY,EACZE,EAAY,EACZD,EAAY,EACZE,EAAY,EAChB,MAAMS,EAAWzG,KAAKD,IAAIQ,GAAcvE,OACxC,IAAK,IAAIyE,EAAY,EAAGA,EAAYgG,EAAUhG,IAAa,CACzD,MAAMC,EAAkBV,KAAKD,IAAIQ,GAAcE,GAAa,EAG/C,IAATD,GAAuB,IAATA,GAChBqF,GAAa1G,EAAkBuB,GAAmBO,EAAsBR,GACxEsF,GAAazB,EAAkB5D,GAAmBO,EAAsBR,IAGxD,IAATD,GAAuB,IAATA,IACrBsF,GAAa3G,EAAkBuB,GAAmBQ,EAAsBT,GACxEuF,GAAa1B,EAAkB5D,GAAmBQ,EAAsBT,GAE3E,CAGD,IAAIwH,EAEFA,EADW,IAATzH,GAAuB,IAATA,EACMvE,KAAKC,KAAK2J,GAAa,EAAIE,GAAa,GAExC9J,KAAKC,KAAK4J,GAAa,EAAIE,GAAa,GAGhE,IACE,IAAIU,EAAiBoB,EACrBpB,EAAiBqB,EACjBrB,GAAkBsB,EAClB,CACA,IAAItH,EAAkBV,KAAKD,IAAIQ,GAAcmG,GAAkB,EAC/DtK,EACE,qDAAqDsE,EAAkB,cACrEH,EAAe,iBACDmG,EAAiB,MAInC7J,EAAe6D,KACZ2E,EAAa8C,GACdF,EACAjH,EAAc0F,GACdgB,EACAC,EAEF,IACE,IAAIX,EAAkBc,EACtBd,EAAkBe,EAClBf,GAAmBgB,EACnB,CACA,IAAIE,EAAmBlI,KAAKD,IAAIQ,GAAcyG,GAAmB,EACjEpK,EAAe8D,GAAiBwH,KAC7B7C,EAAa8C,GACdF,EACAjH,EAAc0F,GACd1F,EAAcgG,GACdU,CACH,CACF,CACF,CACF,GAEJ,IAGN;;;;;;ACjbH,MAAMU,EAAcC,OAAO,iBACrBC,EAAiBD,OAAO,oBACxBE,EAAeF,OAAO,wBACtBG,EAAYH,OAAO,qBACnBI,EAAcJ,OAAO,kBACrBK,EAAYC,GAAwB,iBAARA,GAA4B,OAARA,GAAgC,mBAARA,EAgDxEC,EAAmB,IAAIC,IAAI,CAC7B,CAAC,QA7CwB,CACzBC,UAAYH,GAAQD,EAASC,IAAQA,EAAIP,GACzC,SAAAW,CAAUC,GACN,MAAMC,MAAEA,EAAKC,MAAEA,GAAU,IAAIC,eAE7B,OADAC,EAAOJ,EAAKC,GACL,CAACC,EAAO,CAACA,GACnB,EACDG,YAAYC,IACRA,EAAKC,QACEC,EAAKF,MAqChB,CAAC,QA/BwB,CACzBR,UAAYxI,GAAUoI,EAASpI,IAAUmI,KAAenI,EACxD,SAAAyI,EAAUzI,MAAEA,IACR,IAAImJ,EAcJ,OAZIA,EADAnJ,aAAiBoJ,MACJ,CACTC,SAAS,EACTrJ,MAAO,CACHjE,QAASiE,EAAMjE,QACfgH,KAAM/C,EAAM+C,KACZuG,MAAOtJ,EAAMsJ,QAKR,CAAED,SAAS,EAAOrJ,SAE5B,CAACmJ,EAAY,GACvB,EACD,WAAAJ,CAAYI,GACR,GAAIA,EAAWE,QACX,MAAMzJ,OAAO2J,OAAO,IAAIH,MAAMD,EAAWnJ,MAAMjE,SAAUoN,EAAWnJ,OAExE,MAAMmJ,EAAWnJ,KACpB,MAoBL,SAAS8I,EAAOJ,EAAKc,EAAKC,WAAYC,EAAiB,CAAC,MACpDF,EAAGG,iBAAiB,WAAW,SAASC,EAASC,GAC7C,IAAKA,IAAOA,EAAGC,KACX,OAEJ,IAhBR,SAAyBJ,EAAgBK,GACrC,IAAK,MAAMC,KAAiBN,EAAgB,CACxC,GAAIK,IAAWC,GAAmC,MAAlBA,EAC5B,OAAO,EAEX,GAAIA,aAAyBC,QAAUD,EAAcE,KAAKH,GACtD,OAAO,CAEd,CACD,OAAO,CACX,CAMaI,CAAgBT,EAAgBG,EAAGE,QAEpC,YADA/N,QAAQoO,KAAK,mBAAmBP,EAAGE,6BAGvC,MAAMM,GAAEA,EAAEC,KAAEA,EAAIC,KAAEA,GAAS3K,OAAO2J,OAAO,CAAEgB,KAAM,IAAMV,EAAGC,MACpDU,GAAgBX,EAAGC,KAAKU,cAAgB,IAAIC,IAAIC,GACtD,IAAIC,EACJ,IACI,MAAMC,EAASL,EAAKM,MAAM,GAAI,GAAGC,QAAO,CAACpC,EAAKjG,IAASiG,EAAIjG,IAAOiG,GAC5DqC,EAAWR,EAAKO,QAAO,CAACpC,EAAKjG,IAASiG,EAAIjG,IAAOiG,GACvD,OAAQ4B,GACJ,IAAK,MAEGK,EAAcI,EAElB,MACJ,IAAK,MAEGH,EAAOL,EAAKM,OAAO,GAAG,IAAMH,EAAcb,EAAGC,KAAK9J,OAClD2K,GAAc,EAElB,MACJ,IAAK,QAEGA,EAAcI,EAASC,MAAMJ,EAAQJ,GAEzC,MACJ,IAAK,YAGGG,EA+LxB,SAAejC,GACX,OAAO9I,OAAO2J,OAAOb,EAAK,CAAEZ,CAACA,IAAc,GAC/C,CAjMsCmD,CADA,IAAIF,KAAYP,IAGlC,MACJ,IAAK,WACD,CACI,MAAM7B,MAAEA,EAAKC,MAAEA,GAAU,IAAIC,eAC7BC,EAAOJ,EAAKE,GACZ+B,EAoLxB,SAAkBjC,EAAKwC,GAEnB,OADAC,EAAcC,IAAI1C,EAAKwC,GAChBxC,CACX,CAvLsC2C,CAAS1C,EAAO,CAACA,GAClC,CACD,MACJ,IAAK,UAEGgC,OAAcrI,EAElB,MACJ,QACI,OAEX,CACD,MAAOtC,GACH2K,EAAc,CAAE3K,QAAOmI,CAACA,GAAc,EACzC,CACDmD,QAAQC,QAAQZ,GACXa,OAAOxL,IACD,CAAEA,QAAOmI,CAACA,GAAc,MAE9BsD,MAAMd,IACP,MAAOe,EAAWC,GAAiBC,EAAYjB,GAC/CnB,EAAGqC,YAAYjM,OAAO2J,OAAO3J,OAAO2J,OAAO,GAAImC,GAAY,CAAErB,OAAOsB,GACvD,YAATrB,IAEAd,EAAGsC,oBAAoB,UAAWlC,GAClCmC,EAAcvC,GACVtB,KAAaQ,GAAiC,mBAAnBA,EAAIR,IAC/BQ,EAAIR,KAEX,IAEAsD,OAAOQ,IAER,MAAON,EAAWC,GAAiBC,EAAY,CAC3C5L,MAAO,IAAIiM,UAAU,+BACrB9D,CAACA,GAAc,IAEnBqB,EAAGqC,YAAYjM,OAAO2J,OAAO3J,OAAO2J,OAAO,GAAImC,GAAY,CAAErB,OAAOsB,EAAc,GAE9F,IACQnC,EAAGP,OACHO,EAAGP,OAEX,CAIA,SAAS8C,EAAcG,IAHvB,SAAuBA,GACnB,MAAqC,gBAA9BA,EAAS3M,YAAYwD,IAChC,EAEQoJ,CAAcD,IACdA,EAASE,OACjB,CACA,SAASlD,EAAKM,EAAI6C,GACd,MAAMC,EAAmB,IAAI/D,IAiB7B,OAhBAiB,EAAGG,iBAAiB,WAAW,SAAuBE,GAClD,MAAMC,KAAEA,GAASD,EACjB,IAAKC,IAASA,EAAKO,GACf,OAEJ,MAAMkC,EAAWD,EAAiBE,IAAI1C,EAAKO,IAC3C,GAAKkC,EAGL,IACIA,EAASzC,EACZ,CACO,QACJwC,EAAiBG,OAAO3C,EAAKO,GAChC,CACT,IACWqC,EAAYlD,EAAI8C,EAAkB,GAAID,EACjD,CACA,SAASM,EAAqBC,GAC1B,GAAIA,EACA,MAAM,IAAIxD,MAAM,6CAExB,CACA,SAASyD,EAAgBrD,GACrB,OAAOsD,EAAuBtD,EAAI,IAAIjB,IAAO,CACzC+B,KAAM,YACPmB,MAAK,KACJM,EAAcvC,EAAG,GAEzB,CACA,MAAMuD,EAAe,IAAIC,QACnBC,EAAkB,yBAA0BxD,YAC9C,IAAIyD,sBAAsB1D,IACtB,MAAM2D,GAAYJ,EAAaP,IAAIhD,IAAO,GAAK,EAC/CuD,EAAa3B,IAAI5B,EAAI2D,GACJ,IAAbA,GACAN,EAAgBrD,EACnB,IAcT,SAASkD,EAAYlD,EAAI8C,EAAkB/B,EAAO,GAAI8B,EAAS,cAC3D,IAAIe,GAAkB,EACtB,MAAMnC,EAAQ,IAAIoC,MAAMhB,EAAQ,CAC5B,GAAAG,CAAIc,EAAS7K,GAET,GADAkK,EAAqBS,GACjB3K,IAASwF,EACT,MAAO,MAXvB,SAAyBgD,GACjBgC,GACAA,EAAgBM,WAAWtC,EAEnC,CAQoBuC,CAAgBvC,GAChB4B,EAAgBrD,GAChB8C,EAAiBmB,QACjBL,GAAkB,CAAI,EAG9B,GAAa,SAAT3K,EAAiB,CACjB,GAAoB,IAAhB8H,EAAK7O,OACL,MAAO,CAAE+P,KAAM,IAAMR,GAEzB,MAAMyC,EAAIZ,EAAuBtD,EAAI8C,EAAkB,CACnDhC,KAAM,MACNC,KAAMA,EAAKE,KAAKkD,GAAMA,EAAEC,eACzBnC,KAAKf,GACR,OAAOgD,EAAEjC,KAAKoC,KAAKH,EACtB,CACD,OAAOhB,EAAYlD,EAAI8C,EAAkB,IAAI/B,EAAM9H,GACtD,EACD,GAAA2I,CAAIkC,EAAS7K,EAAMsI,GACf4B,EAAqBS,GAGrB,MAAOpN,EAAO2L,GAAiBC,EAAYb,GAC3C,OAAO+B,EAAuBtD,EAAI8C,EAAkB,CAChDhC,KAAM,MACNC,KAAM,IAAIA,EAAM9H,GAAMgI,KAAKkD,GAAMA,EAAEC,aACnC5N,SACD2L,GAAeF,KAAKf,EAC1B,EACD,KAAAM,CAAMsC,EAASQ,EAAUC,GACrBpB,EAAqBS,GACrB,MAAMY,EAAOzD,EAAKA,EAAK7O,OAAS,GAChC,GAAIsS,IAAShG,EACT,OAAO8E,EAAuBtD,EAAI8C,EAAkB,CAChDhC,KAAM,aACPmB,KAAKf,GAGZ,GAAa,SAATsD,EACA,OAAOtB,EAAYlD,EAAI8C,EAAkB/B,EAAKM,MAAM,GAAI,IAE5D,MAAOL,EAAcmB,GAAiBsC,EAAiBF,GACvD,OAAOjB,EAAuBtD,EAAI8C,EAAkB,CAChDhC,KAAM,QACNC,KAAMA,EAAKE,KAAKkD,GAAMA,EAAEC,aACxBpD,gBACDmB,GAAeF,KAAKf,EAC1B,EACD,SAAAwD,CAAUZ,EAASS,GACfpB,EAAqBS,GACrB,MAAO5C,EAAcmB,GAAiBsC,EAAiBF,GACvD,OAAOjB,EAAuBtD,EAAI8C,EAAkB,CAChDhC,KAAM,YACNC,KAAMA,EAAKE,KAAKkD,GAAMA,EAAEC,aACxBpD,gBACDmB,GAAeF,KAAKf,EAC1B,IAGL,OA9EJ,SAAuBO,EAAOzB,GAC1B,MAAM2D,GAAYJ,EAAaP,IAAIhD,IAAO,GAAK,EAC/CuD,EAAa3B,IAAI5B,EAAI2D,GACjBF,GACAA,EAAgBkB,SAASlD,EAAOzB,EAAIyB,EAE5C,CAuEImD,CAAcnD,EAAOzB,GACdyB,CACX,CAIA,SAASgD,EAAiBzD,GACtB,MAAM6D,EAAY7D,EAAaC,IAAImB,GACnC,MAAO,CAACyC,EAAU5D,KAAK6D,GAAMA,EAAE,MALnBC,EAK+BF,EAAU5D,KAAK6D,GAAMA,EAAE,KAJ3DhR,MAAMkR,UAAUC,OAAOzD,MAAM,GAAIuD,KAD5C,IAAgBA,CAMhB,CACA,MAAMpD,EAAgB,IAAI6B,QAe1B,SAASpB,EAAY5L,GACjB,IAAK,MAAO+C,EAAM2L,KAAYpG,EAC1B,GAAIoG,EAAQlG,UAAUxI,GAAQ,CAC1B,MAAO2O,EAAiBhD,GAAiB+C,EAAQjG,UAAUzI,GAC3D,MAAO,CACH,CACIsK,KAAM,UACNvH,OACA/C,MAAO2O,GAEXhD,EAEP,CAEL,MAAO,CACH,CACIrB,KAAM,MACNtK,SAEJmL,EAAcqB,IAAIxM,IAAU,GAEpC,CACA,SAAS0K,EAAc1K,GACnB,OAAQA,EAAMsK,MACV,IAAK,UACD,OAAOhC,EAAiBkE,IAAIxM,EAAM+C,MAAMgG,YAAY/I,EAAMA,OAC9D,IAAK,MACD,OAAOA,EAAMA,MAEzB,CACA,SAAS8M,EAAuBtD,EAAI8C,EAAkBsC,EAAK1D,GACvD,OAAO,IAAII,SAASC,IAChB,MAAMlB,EASH,IAAI/M,MAAM,GACZQ,KAAK,GACL2M,KAAI,IAAM9O,KAAKkT,MAAMlT,KAAKmT,SAAW5P,OAAO6P,kBAAkBnB,SAAS,MACvEtK,KAAK,KAXNgJ,EAAiBlB,IAAIf,EAAIkB,GACrB/B,EAAGP,OACHO,EAAGP,QAEPO,EAAGqC,YAAYjM,OAAO2J,OAAO,CAAEc,MAAMuE,GAAM1D,EAAU,GAE7D,wBCpUO,MACL,WAAA3L,GACEG,KAAKsP,aAAe,KACpBtP,KAAKnB,WAAa,GAClBmB,KAAKP,mBAAqB,GAC1BO,KAAKrD,aAAe,UACpBH,EAAS,kCACV,CAED,eAAA+S,CAAgBD,GACdtP,KAAKsP,aAAeA,EACpBlT,EAAS,yBAAyBkT,IACnC,CAED,aAAAE,CAAc3Q,GACZmB,KAAKnB,WAAaA,EAClBzC,EAAS,oCAAoCyC,EAAWC,gBACzD,CAED,oBAAA2Q,CAAqBpP,EAAaqP,GAChC1P,KAAKP,mBAAmBY,GAAeqP,EACvCtT,EAAS,0CAA0CiE,YAAsBqP,EAAU,KACpF,CAED,eAAAC,CAAgBhT,GACdqD,KAAKrD,aAAeA,EACpBP,EAAS,yBAAyBO,IACnC,CAED,KAAAiT,GACE,IAAK5P,KAAKsP,eAAiBtP,KAAKnB,aAAemB,KAAKP,mBAAoB,CACtE,MAAM6M,EAAQ,kFAEd,MADAhQ,QAAQgQ,MAAMA,GACR,IAAI5C,MAAM4C,EACjB,CAED,IAAI1P,EAAiB,GACjBC,EAAiB,GACjBI,EAAiB,GACjBsC,EAAkB,GAClBZ,EAAmB,CAAA,EAOvB,GAFAnC,EAAS,gCACTF,QAAQc,KAAK,oBACa,4BAAtB4C,KAAKsP,aAA4C,CACnD9S,EAAS,iBAAiBwD,KAAKsP,kBAC5B1S,iBAAgBC,iBAAgB8B,oBC/ClC,SAAsCE,EAAYY,GACvDjD,EAAS,mDAGT,MAAMsC,cACJA,EAAaC,aACbA,EAAYC,aACZA,EAAY2C,KACZA,EAAIC,KACJA,EAAI3C,aACJA,EAAYC,WACZA,GACEL,EAIJ,IAAI2G,EADJpJ,EAAS,sBAEa,OAAlB0C,EACF0G,EAAO,IAAI3B,EAAO,CAAE9E,eAAc4C,OAAM1C,eAAcC,eAC3B,OAAlBJ,EACT0G,EAAO,IAAInB,EAAO,CAAEtF,eAAc4C,OAAM3C,eAAc4C,OAAM3C,eAAcC,eAE1EzC,EAAS,+CAIX,MAAMgJ,EAA+BD,EAAK3D,0BAA4B2D,EAAKtG,WAAasG,EAAKzB,eAG7F,IAWI2B,EAAe9G,EAXfO,EAAoBsG,EAA6BtG,kBACjDmF,EAAoBmB,EAA6BnB,kBACjDN,EAAcyB,EAA6BzB,YAC3CO,EAAckB,EAA6BlB,YAC3CxE,EAAM0F,EAA6B1D,eACnCjC,EAAmB2F,EAA6B3F,iBAG/BZ,SAMnBwG,EAAgB3F,EAAI/D,OACpB4C,EAAaO,EAAkBnD,OAG/BI,EAAS,0BAA0BsJ,kBAA8B9G,aAGjE8G,EAAgB3G,GAAkC,OAAlBD,EAAyBE,EAAe,GACxEJ,EAAaoF,GAAiC,OAAlBlF,EAAyByF,EAAc,GAEnEnI,EAAS,2CAA2CsJ,kBAA8B9G,YAIpF,IAUI+G,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EAhBAG,EAAmB,GACnBhB,EAAc,GACdC,EAAe,GACfrE,EAAgB,GAChBC,EAAwB,GACxBC,EAAwB,GACxBmF,EAAsB,GACtBC,EAAsB,GACtBzJ,EAAiB,GACjBD,EAAiB,GAUrB,IAAK,IAAI6D,EAAY,EAAGA,EAAY7B,EAAY6B,IAAa,CAC3D5D,EAAe4D,GAAa,EAC5B7D,EAAe8F,KAAK,IACpB,IAAK,IAAI/B,EAAW,EAAGA,EAAW/B,EAAY+B,IAC5C/D,EAAe6D,GAAWE,GAAY,CAEzC,CAGD,MAAM4F,EAAiB,IAAI3F,EAAe,CACxC9B,gBACAG,iBAUF,IAAIuH,EANyB,IAAItB,EAAqB,CACpDpG,gBACAG,iBAI+CkG,2BACjDC,EAAcoB,EAAsBpB,YACpCC,EAAemB,EAAsBnB,aAGrC,MAAMoB,EAAW1G,EAAI,GAAG/D,OAGxB,IAAK,IAAIuE,EAAe,EAAGA,EAAemF,EAAenF,IAAgB,CACvE,IAAK,IAAImG,EAAiB,EAAGA,EAAiBD,EAAUC,IAEtDN,EAAiBM,GAAkB3G,EAAIQ,GAAcmG,GAAkB,EAIzE,IAAK,IAAIC,EAAmB,EAAGA,EAAmBvB,EAAYpJ,OAAQ2K,IAEpE,GAAsB,OAAlB7H,EAAwB,CAC1B,IAAI8H,EAA+BL,EAAe1F,kBAAkBuE,EAAYuB,IAChF3F,EAAgB4F,EAA6B5F,cAC7CC,EAAwB2F,EAA6B3F,sBACrD0E,EAAe,EACfE,EAAY,EAGZ,IAAK,IAAIa,EAAiB,EAAGA,EAAiBD,EAAUC,IACtDf,GAAgBxG,EAAkBiH,EAAiBM,IAAmB1F,EAAc0F,GACpFb,GACE1G,EAAkBiH,EAAiBM,IAAmBzF,EAAsByF,GAEhFT,EAAcJ,EAGd,IAAK,IAAIa,EAAiB,EAAGA,EAAiBD,EAAUC,IACtDL,EAAoBK,GAAkBzF,EAAsByF,GAAkBT,EAIhF,IAAK,IAAIa,EAAkB,EAAGA,EAAkBL,EAAUK,IAAmB,CAC3E,IAAIC,EAAoBX,EAAiBU,GAGzC,IAAK,IAAIE,EAAkB,EAAGA,EAAkBP,EAAUO,IAAmB,CAC3E,IAAIC,EAAoBb,EAAiBY,GACzCpK,EAAemK,GAAmBE,KAC/B5B,EAAasB,GACdV,GACCI,EAAoBS,GAAmBT,EAAoBW,GAC/D,CACF,CAET,MAAa,GAAsB,OAAlBlI,EACT,IAAK,IAAI+H,EAAmB,EAAGA,EAAmBzB,EAAYpJ,OAAQ6K,IAAoB,CAExF,IAAID,EAA+BL,EAAe1F,kBAChDuE,EAAYuB,GACZvB,EAAYyB,IAEd7F,EAAgB4F,EAA6B5F,cAC7CC,EAAwB2F,EAA6B3F,sBACrDC,EAAwB0F,EAA6B1F,sBACrDyE,EAAe,EACfC,EAAe,EACfC,EAAY,EACZC,EAAY,EACZC,EAAY,EACZC,EAAY,EAGZ,IAAK,IAAIU,EAAiB,EAAGA,EAAiBD,EAAUC,IACtDf,GACExG,EAAkBiH,EAAiBM,IAAmB1F,EAAc0F,GACtEd,GACEtB,EAAkB8B,EAAiBM,IAAmB1F,EAAc0F,GACtEb,GACE1G,EAAkBiH,EAAiBM,IAAmBzF,EAAsByF,GAC9EZ,GACE3G,EAAkBiH,EAAiBM,IAAmBxF,EAAsBwF,GAC9EX,GACEzB,EAAkB8B,EAAiBM,IAAmBzF,EAAsByF,GAC9EV,GACE1B,EAAkB8B,EAAiBM,IAAmBxF,EAAsBwF,GAEhFT,EAAcJ,EAAYG,EAAYF,EAAYC,EAGlD,IAAK,IAAIW,EAAiB,EAAGA,EAAiBD,EAAUC,IAEtDL,EAAoBK,IACjBV,EAAY/E,EAAsByF,GACjCX,EAAY7E,EAAsBwF,IACpCT,EAEFK,EAAoBI,IACjBb,EAAY3E,EAAsBwF,GACjCZ,EAAY7E,EAAsByF,IACpCT,EAIJ,IAAK,IAAIa,EAAkB,EAAGA,EAAkBL,EAAUK,IAAmB,CAC3E,IAAIC,EAAoBX,EAAiBU,GAGzC,IAAK,IAAIE,EAAkB,EAAGA,EAAkBP,EAAUO,IAAmB,CAC3E,IAAIC,EAAoBb,EAAiBY,GACzCpK,EAAemK,GAAmBE,KAC/B5B,EAAasB,GACdtB,EAAawB,GACbZ,GACCI,EAAoBS,GAAmBT,EAAoBW,GAC1DV,EAAoBQ,GAAmBR,EAAoBU,GAChE,CACF,CACF,CAGN,CAGDxK,EAAS,2CACT,MAAMqT,EAA4B,IAAI3I,EACpCzH,EACAK,EACAC,EACAjB,EACAG,GAqBF,OAjBA4Q,EAA0BxI,mCACxBxK,EACAD,EACAwI,EACAC,EACAlG,EACAmF,EACAiC,GAEF/J,EAAS,0CAGTqT,EAA0B1I,qCAAqCtK,EAAgBD,GAC/EJ,EAAS,oDAETA,EAAS,iDAEF,CACLI,iBACAC,iBACA8B,iBAAkB,CAChBQ,oBACAmF,qBAGN,CD7M8DwL,CACtD9P,KAAKnB,WACLmB,KAAKP,qBAKPxC,EAD2BP,EAAkBsD,KAAKrD,aAAcC,EAAgBC,GAC5CI,cAC1C,MAAW,GAA0B,2BAAtB+C,KAAKsP,aAA2C,CACzD9S,EAAS,iBAAiBwD,KAAKsP,gBAG/B,IAAI5P,EAAwB,EAG5B,MAAMlB,EAAU,CACdK,WAAYmB,KAAKnB,WACjBY,mBAAoBO,KAAKP,mBACzBC,sBAAuBA,EACvB/C,aAAcqD,KAAKrD,aACnB4C,mBAGF,KAAOG,GAAyB,GAAG,CAEjClB,EAAQkB,sBAAwBA,EAG5BzC,EAAejB,OAAS,IAC1BwC,EAAQe,gBAAkB,IAAItC,IAGhC,MAAM8S,EAAsBzR,EAAcgH,EAA6B9G,EAAS,IAAK,MAGrF5B,EAAiBmT,EAAoBnT,eACrCC,EAAiBkT,EAAoBlT,eACrC8B,EAAmBoR,EAAoBpR,iBACvC1B,EAAiB8S,EAAoB9S,eAIrCyC,GAAyB,EAC1B,CACF,CAID,OAHApD,QAAQ+B,QAAQ,oBAChB7B,EAAS,6BAEF,CAAES,iBAAgB0B,mBAC1B,2BEvGI,MAKL,WAAAkB,GACEG,KAAKgQ,OAAS,KACdhQ,KAAKiQ,UAAY,KACjBjQ,KAAKkQ,SAAU,EAEflQ,KAAKmQ,aACN,CAOD,iBAAMA,GACJ,IACEnQ,KAAKgQ,OAAS,IAAII,OAAO,IAAIC,IAAI,qBAAsB,oBAAAC,SAAA,IAAAC,QAAA,OAAA,KAAA,QAAAC,YAAAC,KAAAH,SAAAI,eAAA,WAAAJ,SAAAI,cAAAC,QAAAC,eAAAN,SAAAI,cAAAG,KAAA,IAAAR,IAAA,mBAAAC,SAAAQ,SAAAL,MAAkB,CACvE7F,KAAM,WAGR5K,KAAKgQ,OAAOe,QAAWC,IACrB1U,QAAQgQ,MAAM,iCAAkC0E,EAAM,EAExD,MAAMC,EAAgBC,EAAalR,KAAKgQ,QAExChQ,KAAKiQ,gBAAkB,IAAIgB,EAE3BjR,KAAKkQ,SAAU,CAChB,CAAC,MAAO5D,GAEP,MADAhQ,QAAQgQ,MAAM,8BAA+BA,GACvCA,CACP,CACF,CAQD,kBAAM6E,GACJ,OAAInR,KAAKkQ,QAAgBtE,QAAQC,UAE1B,IAAID,SAAQ,CAACC,EAASuF,KAC3B,IAAIC,EAAW,EACf,MAEMC,EAAa,KACjBD,IACIrR,KAAKkQ,QACPrE,IACSwF,GANO,GAOhBD,EAAO,IAAI1H,MAAM,2CAEjB6H,WAAWD,EAAY,IACxB,EAEHA,GAAY,GAEf,CAOD,qBAAM/B,CAAgBD,GAGpB,aAFMtP,KAAKmR,eACX3U,EAAS,8CAA8C8S,KAChDtP,KAAKiQ,UAAUV,gBAAgBD,EACvC,CAOD,mBAAME,CAAc3Q,GAGlB,aAFMmB,KAAKmR,eACX3U,EAAS,wCACFwD,KAAKiQ,UAAUT,cAAc3Q,EACrC,CAQD,0BAAM4Q,CAAqBpP,EAAaqP,GAGtC,aAFM1P,KAAKmR,eACX3U,EAAS,4DAA4D6D,KAC9DL,KAAKiQ,UAAUR,qBAAqBpP,EAAaqP,EACzD,CAOD,qBAAMC,CAAgBhT,GAGpB,aAFMqD,KAAKmR,eACX3U,EAAS,8CAA8CG,KAChDqD,KAAKiQ,UAAUN,gBAAgBhT,EACvC,CAMD,WAAMiT,SACE5P,KAAKmR,eACX3U,EAAS,uDAET,MAAMgV,EAAYC,YAAYC,MACxBC,QAAe3R,KAAKiQ,UAAUL,QAIpC,OADApT,EAAS,4CAFOiV,YAAYC,MAEmCF,GAAa,KAAMI,QAAQ,OACnFD,CACR,CAMD,kBAAME,GAEJ,aADM7R,KAAKmR,eACJnR,KAAKiQ,UAAU4B,cACvB,CAMD,UAAMC,GAEJ,aADM9R,KAAKmR,eACJnR,KAAKiQ,UAAU6B,MACvB,CAKD,SAAAC,GACM/R,KAAKgQ,SACPhQ,KAAKgQ,OAAO+B,YACZ/R,KAAKgQ,OAAS,KACdhQ,KAAKiQ,UAAY,KACjBjQ,KAAKkQ,SAAU,EAElB,mBC9JoB,kCCGG8B,MAAOC,IAC/B,IAAIN,EAAS,CACXxS,kBAAmB,GACnBmF,kBAAmB,GACnBvC,eAAgB,CACdE,aAAc,GACdC,iBAAkB,IAEpBpC,iBAAkB,GAClBL,mBAAoB,GACpBqD,kBAAmB,CAAE,EACrBoP,MAAO,EACPC,OAAO,EACPC,SAAU,IACVpO,YAAa,EACbO,YAAa,EACb5B,gBAAiB,GACjBN,aAAc,CAAE,GAIdgQ,SADgBJ,EAAKK,QAEtBC,MAAM,MACNxH,KAAKyH,GAASA,EAAKC,SACnBC,QAAQF,GAAkB,KAATA,GAAwB,MAATA,IAE/BG,EAAU,GACVC,EAAY,EAEZC,EAAmB,EACnBjU,EAAa,EACbkU,EAAsB,EACtBC,EAAmB,CAAEtM,SAAU,GAC/BuM,EAAoB,EACpBC,EAAW,GACXC,EAA2B,EAE3BC,EAAsB,EAEtBC,EAAyB,EACzBC,EAAsB,CACxBC,IAAK,EACLrQ,IAAK,EACLsQ,YAAa,EACbC,YAAa,GAEXC,EAA2B,EAE3BC,EAAwB,CAAA,EAE5B,KAAOd,EAAYP,EAAMrW,QAAQ,CAC/B,MAAMwW,EAAOH,EAAMO,GAEnB,GAAa,gBAATJ,EAAwB,CAC1BG,EAAU,aACVC,IACA,QACN,CAAW,GAAa,mBAATJ,EAA2B,CACpCG,EAAU,GACVC,IACA,QACN,CAAW,GAAa,mBAATJ,EAA2B,CACpCG,EAAU,gBACVC,IACA,QACN,CAAW,GAAa,sBAATJ,EAA8B,CACvCG,EAAU,GACVC,IACA,QACN,CAAW,GAAa,cAATJ,EAAsB,CAC/BG,EAAU,WACVC,IACA,QACN,CAAW,GAAa,iBAATJ,EAAyB,CAClCG,EAAU,GACVC,IACA,QACN,CAAW,GAAa,WAATJ,EAAmB,CAC5BG,EAAU,QACVC,IACA,QACN,CAAW,GAAa,cAATJ,EAAsB,CAC/BG,EAAU,GACVC,IACA,QACN,CAAW,GAAa,cAATJ,EAAsB,CAC/BG,EAAU,WACVC,IACA,QACN,CAAW,GAAa,iBAATJ,EAAyB,CAClCG,EAAU,GACVC,IACA,QACD,CAED,MAAMe,EAAQnB,EAAKD,MAAM,OAAOG,QAAQkB,GAAkB,KAATA,IAEjD,GAAgB,eAAZjB,EACFhB,EAAOO,MAAQ2B,WAAWF,EAAM,IAChChC,EAAOQ,MAAqB,MAAbwB,EAAM,GACrBhC,EAAOS,SAAWuB,EAAM,QACnB,GAAgB,kBAAZhB,GACT,GAAIgB,EAAM3X,QAAU,EAAG,CACrB,IAAK,QAAQwO,KAAKmJ,EAAM,IAAK,CAC3Bf,IACA,QACD,CAED,MAAM5P,EAAY8Q,SAASH,EAAM,GAAI,IAC/B1Q,EAAM6Q,SAASH,EAAM,GAAI,IAC/B,IAAItQ,EAAOsQ,EAAMxI,MAAM,GAAGvH,KAAK,KAC/BP,EAAOA,EAAK0Q,QAAQ,SAAU,IAE9BpC,EAAOhP,gBAAgBD,KAAK,CAC1BO,MACAD,YACAK,QAEH,OACI,GAAgB,UAAZsP,EAAqB,CAC9B,GAAyB,IAArBE,EAAwB,CAC1BA,EAAmBiB,SAASH,EAAM,GAAI,IACtC/U,EAAakV,SAASH,EAAM,GAAI,IAChChC,EAAOxS,kBAAoB,IAAIvB,MAAMgB,GAAYR,KAAK,GACtDuT,EAAOrN,kBAAoB,IAAI1G,MAAMgB,GAAYR,KAAK,GACtDwU,IACA,QACD,CAED,GAAIE,EAAsBD,GAAkD,IAA9BE,EAAiBtM,SAAgB,CAC7EsM,EAAmB,CACjBO,IAAKQ,SAASH,EAAM,GAAI,IACxB1Q,IAAK6Q,SAASH,EAAM,GAAI,IACxBK,WAAYF,SAASH,EAAM,GAAI,IAC/BlN,SAAUqN,SAASH,EAAM,GAAI,KAG/BV,EAAW,GACXD,EAAoB,EACpBE,EAA2B,EAE3BN,IACA,QACD,CAED,GAAII,EAAoBD,EAAiBtM,SAAU,CACjD,IAAK,IAAI1K,EAAI,EAAGA,EAAI4X,EAAM3X,QAAUgX,EAAoBD,EAAiBtM,SAAU1K,IACjFkX,EAASvQ,KAAKoR,SAASH,EAAM5X,GAAI,KACjCiX,IAGF,GAAIA,EAAoBD,EAAiBtM,SAAU,CACjDmM,IACA,QACD,CAEDA,IACA,QACD,CAED,GAAIM,EAA2BH,EAAiBtM,SAAU,CACxD,MAAMwN,EAAUhB,EAASC,GAA4B,EAC/CxV,EAAImW,WAAWF,EAAM,IACrBO,EAAIL,WAAWF,EAAM,IAE3BhC,EAAOxS,kBAAkB8U,GAAWvW,EACpCiU,EAAOrN,kBAAkB2P,GAAWC,EACpCvC,EAAO3N,cACP2N,EAAOpN,cAEP2O,IAEIA,IAA6BH,EAAiBtM,WAChDqM,IACAC,EAAmB,CAAEtM,SAAU,GAElC,CACP,MAAW,GAAgB,aAAZkM,EAAwB,CACjC,GAA4B,IAAxBQ,EAA2B,CAC7BA,EAAsBW,SAASH,EAAM,GAAI,IACzBG,SAASH,EAAM,GAAI,IACnCf,IACA,QACD,CAED,GAAIQ,EAAyBD,GAA2D,IAApCE,EAAoBG,YAAmB,CACzFH,EAAsB,CACpBC,IAAKQ,SAASH,EAAM,GAAI,IACxB1Q,IAAK6Q,SAASH,EAAM,GAAI,IACxBJ,YAAaO,SAASH,EAAM,GAAI,IAChCH,YAAaM,SAASH,EAAM,GAAI,KAGlChC,EAAOtP,aAAagR,EAAoBE,cACrC5B,EAAOtP,aAAagR,EAAoBE,cAAgB,GAAKF,EAAoBG,YAEpFC,EAA2B,EAC3Bb,IACA,QACD,CAED,GAAIa,EAA2BJ,EAAoBG,YAAa,CAC3CM,SAASH,EAAM,GAAI,IACtC,MAAMQ,EAAcR,EAAMxI,MAAM,GAAGJ,KAAKqJ,GAAQN,SAASM,EAAK,MAE9D,GAAwC,IAApCf,EAAoBE,aAAyD,IAApCF,EAAoBE,YAAmB,CAClF,MAAMc,EAAchB,EAAoBpQ,IAEnCyQ,EAAsBW,KACzBX,EAAsBW,GAAe,IAGvCX,EAAsBW,GAAa3R,KAAKyR,GAGnCxC,EAAO7O,kBAAkBuR,KAC5B1C,EAAO7O,kBAAkBuR,GAAe,IAE1C1C,EAAO7O,kBAAkBuR,GAAa3R,KAAKyR,EACrD,MAAuD,IAApCd,EAAoBE,YAE7B5B,EAAO5P,eAAeG,iBAAiBQ,KAAKyR,IACC,IAApCd,EAAoBE,aAGgB,KAApCF,EAAoBE,cAD7B5B,EAAO5P,eAAeE,aAAaS,KAAKyR,GAM1CV,IAEIA,IAA6BJ,EAAoBG,cACnDJ,IACAC,EAAsB,CAAEG,YAAa,GAExC,CACF,CAEDZ,GACD,CAuBD,OApBAjB,EAAOhP,gBAAgBvC,SAAS2C,IAC9B,GAAuB,IAAnBA,EAAKC,UAAiB,CACxB,MAAMsR,EAAgBZ,EAAsB3Q,EAAKE,MAAQ,GAErDqR,EAActY,OAAS,GACzB2V,EAAOlS,mBAAmBiD,KAAK,CAC7BW,KAAMN,EAAKM,KACXJ,IAAKF,EAAKE,IACVsR,MAAOD,GAGZ,KAGHlY,EACE,+CAA+C+F,KAAKC,UAClDuP,EAAO7O,2FAIJ6O,CAAM,oBhBxQR,SAAmB6C,GACV,UAAVA,GAA+B,UAAVA,GACvBlY,QAAQC,IACN,+BAAiCiY,EAAQ,yBACzC,sCAEFrY,EAAkB,UAElBA,EAAkBqY,EAClBhY,EAAS,qBAAqBgY,KAElC,uBiBRO,SACLvX,EACA0B,EACA2Q,EACAxQ,EACA2V,EACAC,EACAC,EAAW,cAEX,MAAMxV,kBAAEA,EAAiBmF,kBAAEA,GAAsB3F,EAEjD,GAAsB,OAAlBG,GAAuC,SAAb2V,EAAqB,CAEjD,IAAIG,EAEFA,EADE3X,EAAejB,OAAS,GAAK4B,MAAMoE,QAAQ/E,EAAe,IACpDA,EAAe8N,KAAK8D,GAAQA,EAAI,KAEhC5R,EAEV,IAAI4X,EAAQjX,MAAMkX,KAAK3V,GAEnB4V,EAAW,CACbrX,EAAGmX,EACHX,EAAGU,EACHI,KAAM,QACNpK,KAAM,UACN4H,KAAM,CAAEyC,MAAO,mBAAoBC,MAAO,GAC1C7R,KAAM,YAGJ8R,EAAiBlZ,KAAKmZ,IAAIC,OAAOC,WAAY,KAC7CC,EAAetZ,KAAKgC,OAAO4W,GAC3BW,EAAaL,EAAiBI,EAI9BE,EAAS,CACXC,MAAO,eAAepG,IACtB4F,MALcjZ,KAAKgC,IAAIuX,EAAaD,EAAc,KAMlDI,OALe,IAMfC,MAAO,CAAEF,MAAO,KAChBG,MAAO,CAAEH,MAAO,YAChBI,OAAQ,CAAEC,EAAG,GAAI/H,EAAG,GAAIgI,EAAG,GAAIC,EAAG,KAGpCC,OAAOC,QAAQzB,EAAW,CAACK,GAAWU,EAAQ,CAAEW,YAAY,GAC7D,MAAM,GAAsB,OAAlBtX,GAAuC,YAAb2V,EAAwB,CAE3D,MAAM4B,EAA4B,eAAb1B,EAGf2B,EAAgB,IAAIC,IAAIpX,GAAmBqX,KAC3CC,EAAgB,IAAIF,IAAIjS,GAAmBkS,KAGjD,IAAIE,EAEFA,EADE9Y,MAAMoE,QAAQ/E,EAAe,IACrBA,EAAe8N,KAAIpC,GAAOA,EAAI,KAE9B1L,EAIZ,IAAIkY,EAAiBlZ,KAAKmZ,IAAIC,OAAOC,WAAY,KAC7C3T,EAAO1F,KAAKgC,OAAOkB,GAEnBwX,EADO1a,KAAKgC,OAAOqG,GACE3C,EACrBiV,EAAY3a,KAAKmZ,IAAID,EAAgB,KAIrCM,EAAS,CACXC,MAAO,GAAGjB,YAAmBnF,IAC7B4F,MAAO0B,EACPjB,OANeiB,EAAYD,EAAc,GAOzCf,MAAO,CAAEF,MAAO,KAChBG,MAAO,CAAEH,MAAO,KAChBI,OAAQ,CAAEC,EAAG,GAAI/H,EAAG,GAAIgI,EAAG,GAAIC,EAAG,IAClCY,UAAW,WAGb,GAAIR,EAAc,CAEhB,MAAMS,EAAYR,EACZS,EAAYN,EAGSpZ,KAAK2Z,QAAQpZ,MAAMkX,KAAK3V,GAAoB,CAAC2X,EAAWC,IACnF,IAAIE,EAAuB5Z,KAAK2Z,QAAQpZ,MAAMkX,KAAKxQ,GAAoB,CAACwS,EAAWC,IAG/EG,EAAmB7Z,KAAK2Z,QAAQpZ,MAAMkX,KAAK7X,GAAiB,CAAC6Z,EAAWC,IAGxEI,EAAqB9Z,KAAK+Z,UAAUF,GAGpCG,EAAmB,GACvB,IAAK,IAAItb,EAAI,EAAGA,EAAI+a,EAAYC,EAAWhb,GAAKgb,EAAW,CACzD,IAAIO,EAASnY,EAAkBpD,GAC/Bsb,EAAiB3U,KAAK4U,EACvB,CAGD,IAAIC,EAAc,CAChBC,EAAGL,EACHvM,KAAM,UACN6M,SAAU,CACRC,SAAU,UACVC,YAAY,GAGdC,SAAU,CACRlC,MAAO,YAEThY,EAAG2Z,EACHnD,EAAG+C,EAAqB,GACxB5T,KAAM,kBAIR6S,OAAOC,QAAQzB,EAAW,CAAC6C,GAAc9B,EAAQ,CAAEW,YAAY,GACrE,KAAW,CAEL,IAAImB,EAAc,CAChB7Z,EAAGyB,EACH+U,EAAG5P,EACHkT,EAAGd,EACH9L,KAAM,UACN6M,SAAU,CACRC,SAAU,UACVC,YAAY,GAGdC,SAAU,CACRlC,MAAO,YAETrS,KAAM,kBAIR6S,OAAOC,QAAQzB,EAAW,CAAC6C,GAAc9B,EAAQ,CAAEW,YAAY,GAChE,CACF,CACH,uBjBzGOpE,iBACLxV,EAAS,oDACT,IACE,MAAMqb,QAAuBC,MAAM,iEAC7BC,QAAmBF,EAAeG,OAClCC,EAAmB,IAAIC,KAAKH,EAAWI,OAAOC,UAAUC,MAAMC,iBAEpE,OADA9b,EAAS,4BAA4Byb,KAC9BA,CACR,CAAC,MAAO3L,GAEP,OADA7P,EAAS,wCAA0C6P,GAC5C,iCACR,CACH"} \ No newline at end of file +{"version":3,"file":"feascript.cjs.js","sources":["../src/methods/euclideanNormScript.js","../src/utilities/loggingScript.js","../src/methods/linearSystemSolverScript.js","../src/methods/jacobiSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/mesh/basisFunctionsScript.js","../src/mesh/meshGenerationScript.js","../src/methods/numericalIntegrationScript.js","../src/mesh/meshUtilsScript.js","../src/solvers/genericBoundaryConditionsScript.js","../src/solvers/frontPropagationScript.js","../src/solvers/thermalBoundaryConditionsScript.js","../src/methods/frontalSolverScript.js","../src/solvers/solidHeatTransferScript.js","../src/vendor/comlink.mjs","../src/FEAScript.js","../src/workers/workerScript.js","../src/index.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.js"],"sourcesContent":["// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to calculate the Euclidean norm of a vector\n * @param {array} vector - The input vector\n * @returns {number} The Euclidean norm of the vector\n */\nexport function euclideanNorm(vector) {\n let norm = 0;\n for (let i = 0; i < vector.length; i++) {\n norm += vector[i] * vector[i];\n }\n norm = Math.sqrt(norm);\n return norm;\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Global logging level\nlet currentLogLevel = \"basic\";\n\n/**\n * Function to set the logging system level\n * @param {string} level - Logging level (basic, debug)\n */\nexport function logSystem(level) {\n if (level !== \"basic\" && level !== \"debug\") {\n console.log(\n \"%c[WARN] Invalid log level: \" + level + \". Using basic instead.\",\n \"color: #FFC107; font-weight: bold;\"\n ); // Yellow for warnings\n currentLogLevel = \"basic\";\n } else {\n currentLogLevel = level;\n basicLog(`Log level set to: ${level}`);\n }\n}\n\n/**\n * Function to log debug messages - only logs if level is 'debug'\n * @param {string} message - Message to log\n */\nexport function debugLog(message) {\n if (currentLogLevel === \"debug\") {\n console.log(\"%c[DEBUG] \" + message, \"color: #2196F3; font-weight: bold;\"); // Blue color for debug\n }\n}\n\n/**\n * Function to log basic information - always logs\n * @param {string} message - Message to log\n */\nexport function basicLog(message) {\n console.log(\"%c[INFO] \" + message, \"color: #4CAF50; font-weight: bold;\"); // Green color for basic info\n}\n\n/**\n * Function to log error messages\n * @param {string} message - Message to log\n */\nexport function errorLog(message) {\n console.log(\"%c[ERROR] \" + message, \"color: #F44336; font-weight: bold;\"); // Red color for errors\n}\n\n/**\n * Function to handle version information and fetch the latest update date and release from GitHub\n */\nexport async function printVersion() {\n basicLog(\"Fetching latest FEAScript version information...\");\n try {\n const commitResponse = await fetch(\"https://api.github.com/repos/FEAScript/FEAScript/commits/main\");\n const commitData = await commitResponse.json();\n const latestCommitDate = new Date(commitData.commit.committer.date).toLocaleString();\n basicLog(`Latest FEAScript update: ${latestCommitDate}`);\n return latestCommitDate;\n } catch (error) {\n errorLog(\"Failed to fetch version information: \" + error);\n return \"Version information unavailable\";\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiSolver } from \"./jacobiSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to solve a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (\"lusolve\" or \"jacobi\")\n * @param {Array} jacobianMatrix - The coefficient matrix\n * @param {Array} residualVector - The right-hand side vector\n * @param {object} [options] - Additional options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum iterations for iterative methods\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance for iterative methods\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - converged: Boolean indicating whether the method converged (for iterative methods)\n * - iterations: Number of iterations performed (for iterative methods)\n */\nexport function solveLinearSystem(solverMethod, jacobianMatrix, residualVector, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n\n let solutionVector = [];\n let converged = true;\n let iterations = 0;\n\n // Solve the linear system based on the specified solver method\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n if (solverMethod === \"lusolve\") {\n // Use LU decomposition method\n const jacobianMatrixSparse = math.sparse(jacobianMatrix);\n const luFactorization = math.slu(jacobianMatrixSparse, 1, 1); // order=1, threshold=1 for pivoting\n let solutionMatrix = math.lusolve(luFactorization, residualVector);\n solutionVector = math.squeeze(solutionMatrix).valueOf();\n //solutionVector = math.lusolve(jacobianMatrix, residualVector); // In the case of a dense matrix\n } else if (solverMethod === \"jacobi\") {\n // Use Jacobi method\n const initialGuess = new Array(residualVector.length).fill(0);\n const jacobiSolverResult = jacobiSolver(jacobianMatrix, residualVector, initialGuess, {\n maxIterations,\n tolerance,\n });\n\n // Log convergence information\n if (jacobiSolverResult.converged) {\n debugLog(`Jacobi method converged in ${jacobiSolverResult.iterations} iterations`);\n } else {\n debugLog(`Jacobi method did not converge after ${jacobiSolverResult.iterations} iterations`);\n }\n\n solutionVector = jacobiSolverResult.solutionVector;\n converged = jacobiSolverResult.converged;\n iterations = jacobiSolverResult.iterations;\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n return { solutionVector, converged, iterations };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method\n * @param {array} jacobianMatrix - The coefficient matrix (must be square)\n * @param {array} residualVector - The right-hand side vector\n * @param {array} initialGuess - Initial guess for solution vector\n * @param {object} [options] - Options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum number of iterations\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\nexport function jacobiSolver(jacobianMatrix, residualVector, initialGuess, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n const n = jacobianMatrix.length; // Size of the square matrix\n let x = [...initialGuess]; // Current solution (starts with initial guess)\n let xNew = new Array(n); // Next iteration's solution\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n // Perform one iteration\n for (let i = 0; i < n; i++) {\n let sum = 0;\n // Calculate sum of jacobianMatrix[i][j] * x[j] for j ≠ i\n for (let j = 0; j < n; j++) {\n if (j !== i) {\n sum += jacobianMatrix[i][j] * x[j];\n }\n }\n // Update xNew[i] using the Jacobi formula\n xNew[i] = (residualVector[i] - sum) / jacobianMatrix[i][i];\n }\n\n // Check convergence\n let maxDiff = 0;\n for (let i = 0; i < n; i++) {\n maxDiff = Math.max(maxDiff, Math.abs(xNew[i] - x[i]));\n }\n\n // Update x for next iteration\n x = [...xNew];\n\n // Successfully converged if maxDiff is less than tolerance\n if (maxDiff < tolerance) {\n return {\n solutionVector: x,\n iterations: iteration + 1,\n converged: true,\n };\n }\n }\n\n // maxIterations were reached without convergence\n return {\n solutionVector: x,\n iterations: maxIterations,\n converged: false,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { euclideanNorm } from \"../methods/euclideanNormScript.js\";\nimport { solveLinearSystem } from \"./linearSystemSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to solve a system of non-linear equations using the Newton-Raphson method\n * @param {number} [maxIterations=100] - Maximum number of iterations\n * @param {number} [tolerance=1e-4] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\n\nexport function newtonRaphson(assembleMat, context, maxIterations = 100, tolerance = 1e-4) {\n let errorNorm = 0;\n let converged = false;\n let iterations = 0;\n let deltaX = [];\n let solutionVector = [];\n let jacobianMatrix = [];\n let residualVector = [];\n\n // Calculate system size from meshData instead of meshConfig\n let totalNodes = context.meshData.nodesXCoordinates.length;\n\n // Initialize arrays with proper size\n for (let i = 0; i < totalNodes; i++) {\n deltaX[i] = 0;\n solutionVector[i] = 0;\n }\n\n // Initialize solution from context if available\n if (context.initialSolution && context.initialSolution.length === totalNodes) {\n solutionVector = [...context.initialSolution];\n }\n\n while (iterations < maxIterations && !converged) {\n // Update solution\n for (let i = 0; i < solutionVector.length; i++) {\n solutionVector[i] = Number(solutionVector[i]) + Number(deltaX[i]);\n }\n\n // Compute Jacobian and residual matrices\n ({ jacobianMatrix, residualVector } = assembleMat(\n context.meshData,\n context.boundaryConditions,\n solutionVector, // The solution vector is required in the case of a non-linear equation\n context.eikonalActivationFlag // Currently used only in the front propagation solver (TODO refactor in case of a solver not needing it)\n ));\n\n // Solve the linear system based on the specified solver method\n const linearSystemResult = solveLinearSystem(context.solverMethod, jacobianMatrix, residualVector);\n deltaX = linearSystemResult.solutionVector;\n\n // Check convergence\n errorNorm = euclideanNorm(deltaX);\n\n // Norm for each iteration\n basicLog(`Newton-Raphson iteration ${iterations + 1}: Error norm = ${errorNorm.toExponential(4)}`);\n\n if (errorNorm <= tolerance) {\n converged = true;\n } else if (errorNorm > 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n errorLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n // Validate geometry parameters (when not using a parsed mesh)\n if (\n !parsedMesh &&\n (this.numElementsX === null || this.maxX === null || this.numElementsY === null || this.maxY === null)\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nimport { BasisFunctions } from \"./basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"./meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to prepare the mesh for finite element analysis\n * @param {object} meshConfig - Object containing computational mesh details\n * @returns {object} An object containing all mesh-related data\n */\nexport function prepareMesh(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, maxX, maxY, elementOrder, parsedMesh } = meshConfig;\n\n // Create a new instance of the Mesh class\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nop,\n boundaryElements,\n totalElements,\n totalNodes,\n meshDimension,\n elementOrder,\n };\n}\n\n/**\n * Function to initialize the FEA matrices and numerical tools\n * @param {object} meshData - Object containing mesh data from prepareMesh()\n * @returns {object} An object containing initialized matrices and numerical tools\n */\nexport function initializeFEA(meshData) {\n const { totalNodes, nop, meshDimension, elementOrder } = meshData;\n\n // Initialize variables for matrix assembly\n let residualVector = [];\n let jacobianMatrix = [];\n let localToGlobalMap = [];\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n let gaussPoints = gaussPointsAndWeights.gaussPoints;\n let gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n return {\n residualVector,\n jacobianMatrix,\n localToGlobalMap,\n basisFunctions,\n gaussPoints,\n gaussWeights,\n numNodes,\n };\n}\n\n/**\n * Function to perform isoparametric mapping for 1D elements\n * @param {object} params - Parameters for the mapping\n * @returns {object} An object containing the mapped data\n */\nexport function performIsoparametricMapping1D(params) {\n const { basisFunction, basisFunctionDerivKsi, nodesXCoordinates, localToGlobalMap, numNodes } = params;\n\n let xCoordinates = 0;\n let ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n let detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n let basisFunctionDerivX = [];\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian;\n }\n\n return {\n xCoordinates,\n detJacobian,\n basisFunctionDerivX,\n };\n}\n\n/**\n * Function to perform isoparametric mapping for 2D elements\n * @param {object} params - Parameters for the mapping\n * @returns {object} An object containing the mapped data\n */\nexport function performIsoparametricMapping2D(params) {\n const {\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n } = params;\n\n let xCoordinates = 0;\n let yCoordinates = 0;\n let ksiDerivX = 0;\n let etaDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates += nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY += nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY += nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n let detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n let basisFunctionDerivX = [];\n let basisFunctionDerivY = [];\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n return {\n xCoordinates,\n yCoordinates,\n detJacobian,\n basisFunctionDerivX,\n basisFunctionDerivY,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport {\n initializeFEA,\n performIsoparametricMapping1D,\n performIsoparametricMapping2D,\n} from \"../mesh/meshUtilsScript.js\";\nimport { basicLog, debugLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the Jacobian matrix and residuals vector for the front propagation model\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n */\nexport function assembleFrontPropagationMat(\n meshData,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n // Calculate eikonal viscous term\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh data\n const {\n nodesXCoordinates,\n nodesYCoordinates,\n nop,\n boundaryElements,\n totalElements,\n meshDimension,\n elementOrder,\n } = meshData;\n\n // Initialize FEA components\n const FEAData = initializeFEA(meshData);\n const {\n residualVector,\n jacobianMatrix,\n localToGlobalMap,\n basisFunctions,\n gaussPoints,\n gaussWeights,\n numNodes,\n } = FEAData;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n // Map local element nodes to global mesh nodes\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n // Get basis functions for the current Gauss point\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n\n // Perform isoparametric mapping\n const mappingResult = performIsoparametricMapping1D({\n basisFunction: basisFunctionsAndDerivatives.basisFunction,\n basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Extract mapping results\n const { detJacobian, basisFunctionDerivX } = mappingResult;\n const basisFunction = basisFunctionsAndDerivatives.basisFunction;\n\n // Calculate solution derivative\n let solutionDerivX = 0;\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n }\n // 2D front propagation (eikonal) equation\n else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Get basis functions for the current Gauss point\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n\n // Perform isoparametric mapping\n const mappingResult = performIsoparametricMapping2D({\n basisFunction: basisFunctionsAndDerivatives.basisFunction,\n basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi,\n basisFunctionDerivEta: basisFunctionsAndDerivatives.basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Extract mapping results\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = mappingResult;\n const basisFunction = basisFunctionsAndDerivatives.basisFunction;\n\n // Calculate solution derivatives\n let solutionDerivX = 0;\n let solutionDerivY = 0;\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n\n // residualVector: Viscous term contribution (to stabilize the solution)\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n\n // residualVector: Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n\n // jacobianMatrix: Viscous term contribution\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n\n // jacobianMatrix: Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]\n ) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2];\n }\n }\n }\n }\n }\n }\n }\n\n // Apply boundary conditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals in debug mode\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { assembleSolidHeatTransferFront } from \"../solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// Add an exported wrapper to obtain results for plotting\nexport function runFrontalSolver(meshConfig, boundaryConditions) {\n main(meshConfig, boundaryConditions);\n return {\n solutionVector: block1.u.slice(0, block1.np),\n nodesCoordinates: {\n nodesXCoordinates: block1.xpt.slice(0, block1.np),\n nodesYCoordinates: block1.ypt.slice(0, block1.np),\n },\n };\n}\n\n// Constants\nconst nemax = 1600;\nconst nnmax = 6724;\nconst nmax = 2000;\n\n// Common block equivalents as objects\nconst block1 = {\n nex: 0,\n ney: 0,\n nnx: 0,\n nny: 0,\n ne: 0,\n np: 0,\n xorigin: 0,\n yorigin: 0,\n xlast: 0,\n ylast: 0,\n deltax: 0,\n deltay: 0,\n nop: Array(nemax)\n .fill()\n .map(() => Array(9).fill(0)),\n xpt: Array(nnmax).fill(0),\n ypt: Array(nnmax).fill(0),\n ncod: Array(nnmax).fill(0),\n bc: Array(nnmax).fill(0),\n r1: Array(nnmax).fill(0),\n u: Array(nnmax).fill(0),\n ntop: Array(nemax).fill(0),\n nlat: Array(nemax).fill(0),\n};\n\nconst gauss = {\n w: [0.27777777777778, 0.444444444444, 0.27777777777778],\n gp: [0.1127016654, 0.5, 0.8872983346],\n};\n\nconst fro1 = {\n iwr1: 0,\n npt: 0,\n ntra: 0,\n nbn: Array(nemax).fill(0),\n det: 1,\n sk: Array(nmax * nmax).fill(0),\n ice1: 0,\n};\n\nconst fabf1 = {\n estifm: Array(9)\n .fill()\n .map(() => Array(9).fill(0)),\n nell: 0,\n};\n\nconst fb1 = {\n ecv: Array(2000000).fill(0),\n lhed: Array(nmax).fill(0),\n qq: Array(nmax).fill(0),\n ecpiv: Array(2000000).fill(0),\n};\n\n// Instantiate shared basis functions handler (biquadratic 2D)\nconst basisFunctionsLib = new BasisFunctions({ meshDimension: \"2D\", elementOrder: \"quadratic\" });\n\n// Main program logic\nfunction main(meshConfig, boundaryConditions) {\n // console.log(\"2-D problem. Biquadratic basis functions\\n\");\n\n xydiscr(meshConfig);\n nodnumb();\n xycoord();\n // console.log(`nex=${block1.nex} ney=${block1.ney} ne=${block1.ne} np=${block1.np}\\n`);\n\n // Initialize all nodes with no boundary condition\n for (let i = 0; i < block1.np; i++) {\n block1.ncod[i] = 0;\n block1.bc[i] = 0;\n }\n\n // Apply boundary conditions based on the boundaryConditions parameter\n Object.keys(boundaryConditions).forEach((boundaryKey) => {\n const condition = boundaryConditions[boundaryKey];\n\n // Handle constantTemp (Dirichlet) boundary conditions\n if (condition[0] === \"constantTemp\") {\n const tempValue = boundaryConditions[boundaryKey][1];\n\n // Apply boundary condition to the appropriate nodes based on boundary key\n switch (boundaryKey) {\n case \"0\": // Bottom boundary (y = yorigin)\n for (let col = 0; col < block1.nnx; col++) {\n const nodeIndex = col * block1.nny;\n block1.ncod[nodeIndex] = 1;\n block1.bc[nodeIndex] = tempValue;\n }\n break;\n\n case \"1\": // Right boundary (x = xlast)\n for (let j = 0; j < block1.nny; j++) {\n block1.ncod[j] = 1;\n block1.bc[j] = tempValue;\n }\n break;\n\n case \"2\": // Top boundary (y = ylast)\n for (let col = 0; col < block1.nnx; col++) {\n const nodeIndex = col * block1.nny + (block1.nny - 1);\n block1.ncod[nodeIndex] = 1;\n block1.bc[nodeIndex] = tempValue;\n }\n break;\n\n case \"3\": // Left boundary (x = xorigin)\n for (let j = 0; j < block1.nny; j++) {\n const nodeIndex = (block1.nnx - 1) * block1.nny + j;\n block1.ncod[nodeIndex] = 1;\n block1.bc[nodeIndex] = tempValue;\n }\n break;\n }\n }\n // Other boundary condition types can be handled later if needed\n });\n\n // Prepare natural boundary conditions\n for (let i = 0; i < block1.ne; i++) {\n block1.ntop[i] = 0;\n block1.nlat[i] = 0;\n }\n\n // for (let i = block1.ney - 1; i < block1.ne; i += block1.ney) {\n // block1.ntop[i] = 1;\n // }\n\n // for (let i = block1.ne - block1.ney; i < block1.ne; i++) {\n // block1.nlat[i] = 1;\n // }\n\n // Initialization\n for (let i = 0; i < block1.np; i++) {\n block1.r1[i] = 0;\n }\n\n fro1.npt = block1.np;\n fro1.iwr1 = 0;\n fro1.ntra = 1;\n fro1.det = 1;\n\n for (let i = 0; i < block1.ne; i++) {\n fro1.nbn[i] = 9;\n }\n\n front();\n\n // Copy solution\n for (let i = 0; i < block1.np; i++) {\n block1.u[i] = fro1.sk[i];\n }\n\n // Output results to console\n for (let i = 0; i < block1.np; i++) {\n debugLog(\n `${block1.xpt[i].toExponential(5)} ${block1.ypt[i].toExponential(5)} ${block1.u[i].toExponential(5)}`\n );\n }\n}\n\n// Discretization\nfunction xydiscr(meshConfig) {\n // Extract values from meshConfig\n const { meshDimension, numElementsX, numElementsY, maxX, maxY, elementOrder, parsedMesh } = meshConfig;\n\n block1.nex = numElementsX;\n block1.ney = numElementsY;\n block1.xorigin = 0;\n block1.yorigin = 0;\n block1.xlast = maxX;\n block1.ylast = maxY;\n block1.deltax = (block1.xlast - block1.xorigin) / block1.nex;\n block1.deltay = (block1.ylast - block1.yorigin) / block1.ney;\n}\n\n// Nodal numbering\nfunction nodnumb() {\n block1.ne = block1.nex * block1.ney;\n block1.nnx = 2 * block1.nex + 1;\n block1.nny = 2 * block1.ney + 1;\n block1.np = block1.nnx * block1.nny;\n\n let nel = 0;\n for (let i = 1; i <= block1.nex; i++) {\n for (let j = 1; j <= block1.ney; j++) {\n nel++;\n for (let k = 1; k <= 3; k++) {\n let l = 3 * k - 2;\n block1.nop[nel - 1][l - 1] = block1.nny * (2 * i + k - 3) + 2 * j - 1;\n block1.nop[nel - 1][l] = block1.nop[nel - 1][l - 1] + 1;\n block1.nop[nel - 1][l + 1] = block1.nop[nel - 1][l - 1] + 2;\n }\n }\n }\n}\n\n// Coordinate setup\nfunction xycoord() {\n block1.xpt[0] = block1.xorigin;\n block1.ypt[0] = block1.yorigin;\n\n for (let i = 1; i <= block1.nnx; i++) {\n let nnode = (i - 1) * block1.nny;\n block1.xpt[nnode] = block1.xpt[0] + ((i - 1) * block1.deltax) / 2;\n block1.ypt[nnode] = block1.ypt[0];\n\n for (let j = 2; j <= block1.nny; j++) {\n block1.xpt[nnode + j - 1] = block1.xpt[nnode];\n block1.ypt[nnode + j - 1] = block1.ypt[nnode] + ((j - 1) * block1.deltay) / 2;\n }\n }\n}\n\n// Element stiffness matrix and residuals (delegated to external assembly function)\nfunction abfind() {\n const elementIndex = fabf1.nell - 1;\n\n const { estifm, localLoad, ngl } = assembleSolidHeatTransferFront({\n elementIndex,\n nop: block1.nop,\n xCoordinates: block1.xpt,\n yCoordinates: block1.ypt,\n basisFunctions: basisFunctionsLib,\n gaussPoints: gauss.gp,\n gaussWeights: gauss.w,\n ntopFlag: block1.ntop[elementIndex] === 1,\n nlatFlag: block1.nlat[elementIndex] === 1,\n });\n\n // Copy element matrix\n for (let i = 0; i < 9; i++) {\n for (let j = 0; j < 9; j++) {\n fabf1.estifm[i][j] = estifm[i][j];\n }\n }\n\n // Accumulate local load into global RHS\n for (let a = 0; a < 9; a++) {\n const g = ngl[a] - 1;\n block1.r1[g] += localLoad[a];\n }\n}\n\n// Frontal solver\nfunction front() {\n let ldest = Array(9).fill(0);\n let kdest = Array(9).fill(0);\n let khed = Array(nmax).fill(0);\n let kpiv = Array(nmax).fill(0);\n let lpiv = Array(nmax).fill(0);\n let jmod = Array(nmax).fill(0);\n let pvkol = Array(nmax).fill(0);\n let eq = Array(nmax)\n .fill()\n .map(() => Array(nmax).fill(0));\n let nrs = Array(nnmax).fill(0);\n let ncs = Array(nnmax).fill(0);\n let check = Array(nnmax).fill(0);\n let lco; // Declare lco once at function scope\n\n let ice = 1;\n fro1.iwr1++;\n let ipiv = 1;\n let nsum = 1;\n fabf1.nell = 0;\n\n for (let i = 0; i < fro1.npt; i++) {\n nrs[i] = 0;\n ncs[i] = 0;\n }\n\n if (fro1.ntra !== 0) {\n // Prefront: find last appearance of each node\n for (let i = 0; i < fro1.npt; i++) {\n check[i] = 0;\n }\n\n for (let i = 0; i < block1.ne; i++) {\n let nep = block1.ne - i - 1;\n for (let j = 0; j < fro1.nbn[nep]; j++) {\n let k = block1.nop[nep][j];\n if (check[k - 1] === 0) {\n check[k - 1] = 1;\n block1.nop[nep][j] = -block1.nop[nep][j];\n }\n }\n }\n }\n\n fro1.ntra = 0;\n let lcol = 0;\n let krow = 0;\n\n for (let i = 0; i < nmax; i++) {\n for (let j = 0; j < nmax; j++) {\n eq[j][i] = 0;\n }\n }\n\n while (true) {\n fabf1.nell++;\n abfind();\n\n let n = fabf1.nell;\n let nend = fro1.nbn[n - 1];\n let lend = fro1.nbn[n - 1];\n\n for (let lk = 0; lk < lend; lk++) {\n let nodk = block1.nop[n - 1][lk];\n let ll;\n\n if (lcol === 0) {\n lcol++;\n ldest[lk] = lcol;\n fb1.lhed[lcol - 1] = nodk;\n } else {\n for (ll = 0; ll < lcol; ll++) {\n if (Math.abs(nodk) === Math.abs(fb1.lhed[ll])) break;\n }\n\n if (ll === lcol) {\n lcol++;\n ldest[lk] = lcol;\n fb1.lhed[lcol - 1] = nodk;\n } else {\n ldest[lk] = ll + 1;\n fb1.lhed[ll] = nodk;\n }\n }\n\n let kk;\n if (krow === 0) {\n krow++;\n kdest[lk] = krow;\n khed[krow - 1] = nodk;\n } else {\n for (kk = 0; kk < krow; kk++) {\n if (Math.abs(nodk) === Math.abs(khed[kk])) break;\n }\n\n if (kk === krow) {\n krow++;\n kdest[lk] = krow;\n khed[krow - 1] = nodk;\n } else {\n kdest[lk] = kk + 1;\n khed[kk] = nodk;\n }\n }\n }\n\n if (krow > nmax || lcol > nmax) {\n errorLog(\"Error: nmax-nsum not large enough\");\n return;\n }\n\n for (let l = 0; l < lend; l++) {\n let ll = ldest[l];\n for (let k = 0; k < nend; k++) {\n let kk = kdest[k];\n eq[kk - 1][ll - 1] += fabf1.estifm[k][l];\n }\n }\n\n let lc = 0;\n for (let l = 0; l < lcol; l++) {\n if (fb1.lhed[l] < 0) {\n lpiv[lc] = l + 1;\n lc++;\n }\n }\n\n let ir = 0;\n let kr = 0;\n for (let k = 0; k < krow; k++) {\n let kt = khed[k];\n if (kt < 0) {\n kpiv[kr] = k + 1;\n kr++;\n let kro = Math.abs(kt);\n if (block1.ncod[kro - 1] === 1) {\n jmod[ir] = k + 1;\n ir++;\n block1.ncod[kro - 1] = 2;\n block1.r1[kro - 1] = block1.bc[kro - 1];\n }\n }\n }\n\n if (ir > 0) {\n for (let irr = 0; irr < ir; irr++) {\n let k = jmod[irr] - 1;\n let kh = Math.abs(khed[k]);\n for (let l = 0; l < lcol; l++) {\n eq[k][l] = 0;\n let lh = Math.abs(fb1.lhed[l]);\n if (lh === kh) eq[k][l] = 1;\n }\n }\n }\n\n if (lc > nsum || fabf1.nell < block1.ne) {\n if (lc === 0) {\n errorLog(\"Error: no more rows fully summed\");\n return;\n }\n\n let kpivro = kpiv[0];\n let lpivco = lpiv[0];\n let pivot = eq[kpivro - 1][lpivco - 1];\n\n if (Math.abs(pivot) < 1e-4) {\n pivot = 0;\n for (let l = 0; l < lc; l++) {\n let lpivc = lpiv[l];\n for (let k = 0; k < kr; k++) {\n let kpivr = kpiv[k];\n let piva = eq[kpivr - 1][lpivc - 1];\n if (Math.abs(piva) > Math.abs(pivot)) {\n pivot = piva;\n lpivco = lpivc;\n kpivro = kpivr;\n }\n }\n }\n }\n\n let kro = Math.abs(khed[kpivro - 1]);\n lco = Math.abs(fb1.lhed[lpivco - 1]); // Assign, don't declare\n let nhlp = kro + lco + nrs[kro - 1] + ncs[lco - 1];\n fro1.det = (fro1.det * pivot * (-1) ** nhlp) / Math.abs(pivot);\n\n for (let iperm = 0; iperm < fro1.npt; iperm++) {\n if (iperm >= kro) nrs[iperm]--;\n if (iperm >= lco) ncs[iperm]--;\n }\n\n if (Math.abs(pivot) < 1e-10) {\n errorLog(\n `Warning: matrix singular or ill-conditioned, nell=${fabf1.nell}, kro=${kro}, lco=${lco}, pivot=${pivot}`\n );\n }\n\n if (pivot === 0) return;\n\n for (let l = 0; l < lcol; l++) {\n fb1.qq[l] = eq[kpivro - 1][l] / pivot;\n }\n\n let rhs = block1.r1[kro - 1] / pivot;\n block1.r1[kro - 1] = rhs;\n pvkol[kpivro - 1] = pivot;\n\n if (kpivro > 1) {\n for (let k = 0; k < kpivro - 1; k++) {\n let krw = Math.abs(khed[k]);\n let fac = eq[k][lpivco - 1];\n pvkol[k] = fac;\n if (lpivco > 1 && fac !== 0) {\n for (let l = 0; l < lpivco - 1; l++) {\n eq[k][l] -= fac * fb1.qq[l];\n }\n }\n if (lpivco < lcol) {\n for (let l = lpivco; l < lcol; l++) {\n eq[k][l - 1] = eq[k][l] - fac * fb1.qq[l];\n }\n }\n block1.r1[krw - 1] -= fac * rhs;\n }\n }\n\n if (kpivro < krow) {\n for (let k = kpivro; k < krow; k++) {\n let krw = Math.abs(khed[k]);\n let fac = eq[k][lpivco - 1];\n pvkol[k] = fac;\n if (lpivco > 1) {\n for (let l = 0; l < lpivco - 1; l++) {\n eq[k - 1][l] = eq[k][l] - fac * fb1.qq[l];\n }\n }\n if (lpivco < lcol) {\n for (let l = lpivco; l < lcol; l++) {\n eq[k - 1][l - 1] = eq[k][l] - fac * fb1.qq[l];\n }\n }\n block1.r1[krw - 1] -= fac * rhs;\n }\n }\n\n for (let i = 0; i < krow; i++) {\n fb1.ecpiv[ipiv + i - 1] = pvkol[i];\n }\n ipiv += krow;\n\n for (let i = 0; i < krow; i++) {\n fb1.ecpiv[ipiv + i - 1] = khed[i];\n }\n ipiv += krow;\n\n fb1.ecpiv[ipiv - 1] = kpivro;\n ipiv++;\n\n for (let i = 0; i < lcol; i++) {\n fb1.ecv[ice - 1 + i] = fb1.qq[i];\n }\n ice += lcol;\n\n for (let i = 0; i < lcol; i++) {\n fb1.ecv[ice - 1 + i] = fb1.lhed[i];\n }\n ice += lcol;\n\n fb1.ecv[ice - 1] = kro;\n fb1.ecv[ice] = lcol;\n fb1.ecv[ice + 1] = lpivco;\n fb1.ecv[ice + 2] = pivot;\n ice += 4;\n\n for (let k = 0; k < krow; k++) {\n eq[k][lcol - 1] = 0;\n }\n\n for (let l = 0; l < lcol; l++) {\n eq[krow - 1][l] = 0;\n }\n\n lcol--;\n if (lpivco < lcol + 1) {\n for (let l = lpivco - 1; l < lcol; l++) {\n fb1.lhed[l] = fb1.lhed[l + 1];\n }\n }\n\n krow--;\n if (kpivro < krow + 1) {\n for (let k = kpivro - 1; k < krow; k++) {\n khed[k] = khed[k + 1];\n }\n }\n\n if (krow > 1 || fabf1.nell < block1.ne) continue;\n\n lco = Math.abs(fb1.lhed[0]); // Assign, don't declare\n kpivro = 1;\n pivot = eq[0][0];\n kro = Math.abs(khed[0]);\n lpivco = 1;\n nhlp = kro + lco + nrs[kro - 1] + ncs[lco - 1];\n fro1.det = (fro1.det * pivot * (-1) ** nhlp) / Math.abs(pivot);\n\n fb1.qq[0] = 1;\n if (Math.abs(pivot) < 1e-10) {\n errorLog(\n `Warning: matrix singular or ill-conditioned, nell=${fabf1.nell}, kro=${kro}, lco=${lco}, pivot=${pivot}`\n );\n }\n\n if (pivot === 0) return;\n\n block1.r1[kro - 1] = block1.r1[kro - 1] / pivot;\n fb1.ecv[ice - 1] = fb1.qq[0];\n ice++;\n fb1.ecv[ice - 1] = fb1.lhed[0];\n ice++;\n fb1.ecv[ice - 1] = kro;\n fb1.ecv[ice] = lcol;\n fb1.ecv[ice + 1] = lpivco;\n fb1.ecv[ice + 2] = pivot;\n ice += 4;\n\n fb1.ecpiv[ipiv - 1] = pvkol[0];\n ipiv++;\n fb1.ecpiv[ipiv - 1] = khed[0];\n ipiv++;\n fb1.ecpiv[ipiv - 1] = kpivro;\n ipiv++;\n\n fro1.ice1 = ice;\n if (fro1.iwr1 === 1) debugLog(`total ecs transfer in matrix reduction=${ice}`);\n\n bacsub(ice);\n break;\n }\n }\n}\n\n// Back substitution\nfunction bacsub(ice) {\n for (let i = 0; i < fro1.npt; i++) {\n fro1.sk[i] = block1.bc[i];\n }\n\n for (let iv = 1; iv <= fro1.npt; iv++) {\n ice -= 4;\n let kro = fb1.ecv[ice - 1];\n let lcol = fb1.ecv[ice];\n let lpivco = fb1.ecv[ice + 1];\n let pivot = fb1.ecv[ice + 2];\n\n if (iv === 1) {\n ice--;\n fb1.lhed[0] = fb1.ecv[ice - 1];\n ice--;\n fb1.qq[0] = fb1.ecv[ice - 1];\n } else {\n ice -= lcol;\n for (let iii = 0; iii < lcol; iii++) {\n fb1.lhed[iii] = fb1.ecv[ice - 1 + iii];\n }\n ice -= lcol;\n for (let iii = 0; iii < lcol; iii++) {\n fb1.qq[iii] = fb1.ecv[ice - 1 + iii];\n }\n }\n\n let lco = Math.abs(fb1.lhed[lpivco - 1]);\n if (block1.ncod[lco - 1] > 0) continue;\n\n let gash = 0;\n fb1.qq[lpivco - 1] = 0;\n for (let l = 0; l < lcol; l++) {\n gash -= fb1.qq[l] * fro1.sk[Math.abs(fb1.lhed[l]) - 1];\n }\n\n fro1.sk[lco - 1] = gash + block1.r1[kro - 1];\n\n block1.ncod[lco - 1] = 1;\n }\n\n if (fro1.iwr1 === 1) debugLog(`value of ice after backsubstitution=${ice}`);\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport {\n initializeFEA,\n performIsoparametricMapping1D,\n performIsoparametricMapping2D,\n} from \"../mesh/meshUtilsScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the Jacobian matrix and residuals vector for the solid heat transfer model\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n */\nexport function assembleSolidHeatTransferMat(meshData, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh data\n const {\n nodesXCoordinates,\n nodesYCoordinates,\n nop,\n boundaryElements,\n totalElements,\n meshDimension,\n elementOrder,\n } = meshData;\n\n // Initialize FEA components\n const FEAData = initializeFEA(meshData);\n const {\n residualVector,\n jacobianMatrix,\n localToGlobalMap,\n basisFunctions,\n gaussPoints,\n gaussWeights,\n numNodes,\n } = FEAData;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n // Map local element nodes to global mesh nodes\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n // Get basis functions for the current Gauss point\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n\n // Perform isoparametric mapping\n const mappingResult = performIsoparametricMapping1D({\n basisFunction: basisFunctionsAndDerivatives.basisFunction,\n basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Extract mapping results\n const { detJacobian, basisFunctionDerivX } = mappingResult;\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n }\n // 2D solid heat transfer\n else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Get basis functions for the current Gauss point\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n\n // Perform isoparametric mapping\n const mappingResult = performIsoparametricMapping2D({\n basisFunction: basisFunctionsAndDerivatives.basisFunction,\n basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi,\n basisFunctionDerivEta: basisFunctionsAndDerivatives.basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Extract mapping results\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = mappingResult;\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Apply boundary conditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n // Print all residuals in debug mode\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n\n/**\n * Function to assemble the local Jacobian matrix and residuals vector for the solid heat transfer model when using the frontal system solver\n */\nexport function assembleSolidHeatTransferFront({\n elementIndex,\n nop,\n xCoordinates,\n yCoordinates,\n basisFunctions,\n gaussPoints,\n gaussWeights,\n ntopFlag = false,\n nlatFlag = false,\n convectionTop = { active: false, coeff: 0, extTemp: 0 }, // NEW\n}) {\n const numNodes = 9; // biquadratic 2D\n const estifm = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localLoad = Array(numNodes).fill(0);\n\n // Global node numbers (1-based in nop)\n const ngl = Array(numNodes);\n for (let i = 0; i < numNodes; i++) ngl[i] = Math.abs(nop[elementIndex][i]);\n\n // Volume (conductive) contribution\n for (let j = 0; j < gaussPoints.length; j++) {\n for (let k = 0; k < gaussPoints.length; k++) {\n const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } =\n basisFunctions.getBasisFunctions(gaussPoints[j], gaussPoints[k]);\n\n const localToGlobalMap = ngl.map((g) => g - 1);\n\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates: xCoordinates,\n nodesYCoordinates: yCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n for (let a = 0; a < numNodes; a++) {\n for (let b = 0; b < numNodes; b++) {\n estifm[a][b] -=\n gaussWeights[j] *\n gaussWeights[k] *\n detJacobian *\n (basisFunctionDerivX[a] * basisFunctionDerivX[b] +\n basisFunctionDerivY[a] * basisFunctionDerivY[b]);\n }\n }\n }\n }\n\n // Legacy natural boundary terms (top edge eta=1; right edge ksi=1) kept as in original frontal version\n // Replace previous generic top-edge load term with explicit Robin (convection) if requested\n if (ntopFlag && convectionTop.active) {\n const h = convectionTop.coeff;\n const Text = convectionTop.extTemp;\n // Integrate along top edge (eta = 1); local top edge nodes: 2,5,8\n for (let gp = 0; gp < gaussPoints.length; gp++) {\n const ksi = gaussPoints[gp];\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(ksi, 1);\n\n // Compute metric (edge length differential) |dx/dksi|\n let dx_dksi = 0, dy_dksi = 0;\n const topEdgeLocalNodes = [2, 5, 8];\n for (let n = 0; n < 9; n++) {\n const g = nop[elementIndex][n] - 1;\n dx_dksi += xCoordinates[g] * basisFunctionDerivKsi[n];\n dy_dksi += yCoordinates[g] * basisFunctionDerivKsi[n];\n }\n const ds_dksi = Math.sqrt(dx_dksi * dx_dksi + dy_dksi * dy_dksi);\n\n // Assemble Robin contributions\n for (const a of topEdgeLocalNodes) {\n for (const b of topEdgeLocalNodes) {\n estifm[a][b] -= gaussWeights[gp] * ds_dksi * h * basisFunction[a] * basisFunction[b];\n }\n localLoad[a] -= gaussWeights[gp] * ds_dksi * h * Text * basisFunction[a];\n }\n }\n } else if (ntopFlag && !convectionTop.active) {\n // If a zero-flux (symmetry) condition were applied on top, do nothing (natural BC)\n // (Previous placeholder load term removed to avoid unintended flux)\n }\n\n // If needed, similar patterned handling could be added for right edge (nlatFlag) later.\n\n return { estifm, localLoad, ngl };\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { prepareMesh } from \"./mesh/meshUtilsScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { runFrontalSolver } from \"./methods/frontalSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n\n // Prepare the mesh\n basicLog(\"Preparing mesh...\");\n const meshData = prepareMesh(this.meshConfig);\n basicLog(\"Mesh preparation completed\");\n\n // Extract node coordinates from meshData\n const nodesCoordinates = {\n nodesXCoordinates: meshData.nodesXCoordinates,\n nodesYCoordinates: meshData.nodesYCoordinates,\n };\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Check if using frontal solver\n if (this.solverMethod === \"frontal\") {\n basicLog(`Using frontal solver method`);\n // Call frontal solver\n const frontalResult = runFrontalSolver(this.meshConfig, this.boundaryConditions);\n solutionVector = frontalResult.solutionVector;\n } else {\n // Use regular linear solver methods\n ({ jacobianMatrix, residualVector } = assembleSolidHeatTransferMat(\n meshData,\n this.boundaryConditions\n ));\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n }\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n const eikonalExteralIterations = 5; // Number of incremental steps for the eikonal equation\n\n // Create context object with all necessary properties\n const context = {\n meshData: meshData,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n // Solve the assembled non-linear system\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n solutionVector = newtonRaphsonResult.solutionVector;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.3\";","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","debugLog","message","console","log","basicLog","errorLog","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","jacobianMatrixSparse","math","sparse","luFactorization","slu","solutionMatrix","lusolve","squeeze","valueOf","jacobiSolverResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiSolver","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","totalNodes","meshData","nodesXCoordinates","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","BasisFunctions","constructor","meshDimension","elementOrder","this","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","numElementsX","maxX","numElementsY","maxY","parsedMesh","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","boundaryElements","undefined","fixedBoundaryElements","boundaryNodePairs","forEach","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","side","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","nodeIndex","generate1DNodalNumbering","findBoundaryElements","nop","elementIndex","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","initializeFEA","colIndex","basisFunctions","gaussPointsAndWeights","localToGlobalMap","numNodes","performIsoparametricMapping1D","params","xCoordinates","ksiDerivX","localNodeIndex","detJacobian","basisFunctionDerivX","performIsoparametricMapping2D","yCoordinates","etaDerivX","ksiDerivY","etaDerivY","basisFunctionDerivY","GenericBoundaryConditions","imposeConstantValueBoundaryConditions","Object","keys","boundaryKey","value","globalNodeIndex","assembleFrontPropagationMat","eikonalViscousTerm","totalElements","FEAData","gaussPointIndex1","basisFunctionsAndDerivatives","mappingResult","solutionDerivX","localNodeIndex1","localNodeIndex2","gaussPointIndex2","solutionDerivY","localToGlobalMap1","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","runFrontalSolver","meshConfig","block1","nex","ney","xorigin","yorigin","xlast","ylast","deltax","deltay","xydiscr","ne","nnx","nny","np","nel","k","l","nodnumb","xpt","ypt","xycoord","ncod","bc","col","ntop","nlat","r1","fro1","npt","iwr1","ntra","det","nbn","lco","ldest","kdest","khed","nmax","kpiv","lpiv","jmod","pvkol","eq","map","nrs","nnmax","ncs","check","ice","ipiv","nsum","fabf1","nell","nep","lcol","krow","abfind","nend","lend","lk","ll","kk","nodk","fb1","lhed","estifm","lc","ir","kr","kt","kro","irr","kh","kpivro","lpivco","pivot","lpivc","kpivr","piva","nhlp","iperm","qq","rhs","krw","fac","ecpiv","ecv","ice1","bacsub","front","u","sk","main","slice","nodesCoordinates","nemax","gauss","w","gp","basisFunctionsLib","localLoad","ngl","ntopFlag","nlatFlag","convectionTop","active","coeff","g","a","b","h","Text","dx_dksi","dy_dksi","topEdgeLocalNodes","ds_dksi","assembleSolidHeatTransferFront","iv","iii","gash","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","Error","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","fromWireValue","returnValue","parent","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","r","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","arr","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","mesh","nodesCoordinatesAndNumbering","prepareMesh","thermalBoundaryConditions","assembleSolidHeatTransferMat","eikonalExteralIterations","newtonRaphsonResult","worker","feaWorker","isReady","_initWorker","Worker","URL","document","require","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","result","toFixed","getModelInfo","ping","terminate","async","file","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","parseInt","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","level","plotType","plotDivId","meshType","yData","xData","from","lineData","mode","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","t","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString"],"mappings":"aAeO,SAASA,EAAcC,GAC5B,IAAIC,EAAO,EACX,IAAK,IAAIC,EAAI,EAAGA,EAAIF,EAAOG,OAAQD,IACjCD,GAAQD,EAAOE,GAAKF,EAAOE,GAG7B,OADAD,EAAOG,KAAKC,KAAKJ,GACVA,CACT,wDCXA,IAAIK,EAAkB,QAuBf,SAASC,EAASC,GACC,UAApBF,GACFG,QAAQC,IAAI,aAAeF,EAAS,qCAExC,CAMO,SAASG,EAASH,GACvBC,QAAQC,IAAI,YAAcF,EAAS,qCACrC,CAMO,SAASI,EAASJ,GACvBC,QAAQC,IAAI,aAAeF,EAAS,qCACtC,CC3BO,SAASK,EAAkBC,EAAcC,EAAgBC,EAAgBC,EAAU,CAAA,GACxF,MAAMC,cAAEA,EAAgB,IAAIC,UAAEA,EAAY,MAASF,EAEnD,IAAIG,EAAiB,GACjBC,GAAY,EACZC,EAAa,EAMjB,GAHAX,EAAS,wBAAwBG,QACjCL,QAAQc,KAAK,iBAEQ,YAAjBT,EAA4B,CAE9B,MAAMU,EAAuBC,KAAKC,OAAOX,GACnCY,EAAkBF,KAAKG,IAAIJ,EAAsB,EAAG,GAC1D,IAAIK,EAAiBJ,KAAKK,QAAQH,EAAiBX,GACnDI,EAAiBK,KAAKM,QAAQF,GAAgBG,SAElD,MAAS,GAAqB,WAAjBlB,EAA2B,CAEpC,MACMmB,ECzBH,SAAsBlB,EAAgBC,EAAgBkB,EAAcjB,EAAU,CAAA,GACnF,MAAMC,cAAEA,EAAgB,IAAIC,UAAEA,EAAY,MAASF,EAC7CkB,EAAIpB,EAAeZ,OACzB,IAAIiC,EAAI,IAAIF,GACRG,EAAO,IAAIC,MAAMH,GAErB,IAAK,IAAII,EAAY,EAAGA,EAAYrB,EAAeqB,IAAa,CAE9D,IAAK,IAAIrC,EAAI,EAAGA,EAAIiC,EAAGjC,IAAK,CAC1B,IAAIsC,EAAM,EAEV,IAAK,IAAIC,EAAI,EAAGA,EAAIN,EAAGM,IACjBA,IAAMvC,IACRsC,GAAOzB,EAAeb,GAAGuC,GAAKL,EAAEK,IAIpCJ,EAAKnC,IAAMc,EAAed,GAAKsC,GAAOzB,EAAeb,GAAGA,EACzD,CAGD,IAAIwC,EAAU,EACd,IAAK,IAAIxC,EAAI,EAAGA,EAAIiC,EAAGjC,IACrBwC,EAAUtC,KAAKuC,IAAID,EAAStC,KAAKwC,IAAIP,EAAKnC,GAAKkC,EAAElC,KAOnD,GAHAkC,EAAI,IAAIC,GAGJK,EAAUvB,EACZ,MAAO,CACLC,eAAgBgB,EAChBd,WAAYiB,EAAY,EACxBlB,WAAW,EAGhB,CAGD,MAAO,CACLD,eAAgBgB,EAChBd,WAAYJ,EACZG,WAAW,EAEf,CDpB+BwB,CAAa9B,EAAgBC,EADnC,IAAIsB,MAAMtB,EAAeb,QAAQ2C,KAAK,GAC2B,CACpF5B,gBACAC,cAIEc,EAAmBZ,UACrBd,EAAS,8BAA8B0B,EAAmBX,yBAE1Df,EAAS,wCAAwC0B,EAAmBX,yBAGtEF,EAAiBa,EAAmBb,eACpCC,EAAYY,EAAmBZ,UAC/BC,EAAaW,EAAmBX,UACpC,MACIV,EAAS,0BAA0BE,KAMrC,OAHAL,QAAQsC,QAAQ,iBAChBpC,EAAS,8BAEF,CAAES,iBAAgBC,YAAWC,aACtC,CE9CO,SAAS0B,EAAcC,EAAaC,EAAShC,EAAgB,IAAKC,EAAY,MACnF,IAAIgC,EAAY,EACZ9B,GAAY,EACZC,EAAa,EACb8B,EAAS,GACThC,EAAiB,GACjBL,EAAiB,GACjBC,EAAiB,GAGjBqC,EAAaH,EAAQI,SAASC,kBAAkBpD,OAGpD,IAAK,IAAID,EAAI,EAAGA,EAAImD,EAAYnD,IAC9BkD,EAAOlD,GAAK,EACZkB,EAAelB,GAAK,EAQtB,IAJIgD,EAAQM,iBAAmBN,EAAQM,gBAAgBrD,SAAWkD,IAChEjC,EAAiB,IAAI8B,EAAQM,kBAGxBlC,EAAaJ,IAAkBG,GAAW,CAE/C,IAAK,IAAInB,EAAI,EAAGA,EAAIkB,EAAejB,OAAQD,IACzCkB,EAAelB,GAAKuD,OAAOrC,EAAelB,IAAMuD,OAAOL,EAAOlD,MAI7Da,iBAAgBC,kBAAmBiC,EACpCC,EAAQI,SACRJ,EAAQQ,mBACRtC,EACA8B,EAAQS,wBAaV,GARAP,EAD2BvC,EAAkBqC,EAAQpC,aAAcC,EAAgBC,GACvDI,eAG5B+B,EAAYpD,EAAcqD,GAG1BzC,EAAS,4BAA4BW,EAAa,mBAAmB6B,EAAUS,cAAc,MAEzFT,GAAahC,EACfE,GAAY,OACP,GAAI8B,EAAY,IAAK,CAC1BvC,EAAS,uCAAuCuC,KAChD,KACD,CAED7B,GACD,CAED,MAAO,CACLF,iBACAC,YACAC,aACAP,iBACAC,iBAEJ,CCzEO,MAAM6C,EAMX,WAAAC,EAAYC,cAAEA,EAAaC,aAAEA,IAC3BC,KAAKF,cAAgBA,EACrBE,KAAKD,aAAeA,CACrB,CAWD,iBAAAE,CAAkBC,EAAKC,EAAM,MAC3B,IAAIC,EAAgB,GAChBC,EAAwB,GACxBC,EAAwB,GAE5B,GAA2B,OAAvBN,KAAKF,cACmB,WAAtBE,KAAKD,cAEPK,EAAc,GAAK,EAAIF,EACvBE,EAAc,GAAKF,EAGnBG,EAAsB,IAAM,EAC5BA,EAAsB,GAAK,GACI,cAAtBL,KAAKD,eAEdK,EAAc,GAAK,EAAI,EAAIF,EAAM,EAAIA,GAAO,EAC5CE,EAAc,GAAK,EAAIF,EAAM,EAAIA,GAAO,EACxCE,EAAc,GAAY,EAAIF,GAAO,EAAjBA,EAGpBG,EAAsB,GAAU,EAAIH,EAAR,EAC5BG,EAAsB,GAAK,EAAI,EAAIH,EACnCG,EAAsB,GAAU,EAAIH,EAAR,QAEzB,GAA2B,OAAvBF,KAAKF,cAAwB,CACtC,GAAY,OAARK,EAEF,YADAxD,EAAS,8CAIX,GAA0B,WAAtBqD,KAAKD,aAA2B,CAElC,SAASQ,EAAGC,GACV,OAAO,EAAIA,CACZ,CAYDJ,EAAc,GAAKG,EAAGL,GAAOK,EAAGJ,GAChCC,EAAc,GAAKG,EAAGL,GAAUC,EAChCC,EAAc,GAAQF,EAAOK,EAAGJ,GAChCC,EAAc,GAAQF,EAAUC,EAGhCE,EAAsB,IAbZ,EAayBE,EAAGJ,GACtCE,EAAsB,IAdZ,EAc4BF,EACtCE,EAAsB,GAZb,EAY0BE,EAAGJ,GACtCE,EAAsB,GAbb,EAa6BF,EAGtCG,EAAsB,IAnBZ,EAmBiBC,EAAGL,GAC9BI,EAAsB,GAjBb,EAiBkBC,EAAGL,GAC9BI,EAAsB,IArBZ,EAqBoBJ,EAC9BI,EAAsB,GAnBb,EAmBqBJ,CACtC,MAAa,GAA0B,cAAtBF,KAAKD,aAA8B,CAE5C,SAASQ,EAAGC,GACV,OAAO,EAAIA,GAAK,EAAI,EAAIA,EAAI,CAC7B,CACD,SAASC,EAAGD,GACV,OAAQ,EAAIA,GAAK,EAAI,EAAIA,CAC1B,CACD,SAASE,EAAGF,GACV,OAAO,EAAIA,GAAK,EAAIA,CACrB,CACD,SAASG,EAAIH,GACX,OAAO,EAAIA,EAAI,CAChB,CACD,SAASI,EAAIJ,GACX,OAAQ,EAAIA,EAAI,CACjB,CACD,SAASK,EAAIL,GACX,OAAO,EAAIA,EAAI,CAChB,CAGDJ,EAAc,GAAKG,EAAGL,GAAOK,EAAGJ,GAChCC,EAAc,GAAKG,EAAGL,GAAOO,EAAGN,GAChCC,EAAc,GAAKG,EAAGL,GAAOQ,EAAGP,GAChCC,EAAc,GAAKK,EAAGP,GAAOK,EAAGJ,GAChCC,EAAc,GAAKK,EAAGP,GAAOO,EAAGN,GAChCC,EAAc,GAAKK,EAAGP,GAAOQ,EAAGP,GAChCC,EAAc,GAAKM,EAAGR,GAAOK,EAAGJ,GAChCC,EAAc,GAAKM,EAAGR,GAAOO,EAAGN,GAChCC,EAAc,GAAKM,EAAGR,GAAOQ,EAAGP,GAGhCE,EAAsB,GAAKM,EAAIT,GAAOK,EAAGJ,GACzCE,EAAsB,GAAKM,EAAIT,GAAOO,EAAGN,GACzCE,EAAsB,GAAKM,EAAIT,GAAOQ,EAAGP,GACzCE,EAAsB,GAAKO,EAAIV,GAAOK,EAAGJ,GACzCE,EAAsB,GAAKO,EAAIV,GAAOO,EAAGN,GACzCE,EAAsB,GAAKO,EAAIV,GAAOQ,EAAGP,GACzCE,EAAsB,GAAKQ,EAAIX,GAAOK,EAAGJ,GACzCE,EAAsB,GAAKQ,EAAIX,GAAOO,EAAGN,GACzCE,EAAsB,GAAKQ,EAAIX,GAAOQ,EAAGP,GAGzCG,EAAsB,GAAKC,EAAGL,GAAOS,EAAIR,GACzCG,EAAsB,GAAKC,EAAGL,GAAOU,EAAIT,GACzCG,EAAsB,GAAKC,EAAGL,GAAOW,EAAIV,GACzCG,EAAsB,GAAKG,EAAGP,GAAOS,EAAIR,GACzCG,EAAsB,GAAKG,EAAGP,GAAOU,EAAIT,GACzCG,EAAsB,GAAKG,EAAGP,GAAOW,EAAIV,GACzCG,EAAsB,GAAKI,EAAGR,GAAOS,EAAIR,GACzCG,EAAsB,GAAKI,EAAGR,GAAOU,EAAIT,GACzCG,EAAsB,GAAKI,EAAGR,GAAOW,EAAIV,EAC1C,CACF,CAED,MAAO,CAAEC,gBAAeC,wBAAuBC,wBAChD,EC5II,MAAMQ,EAYX,WAAAjB,EAAYkB,aACVA,EAAe,KAAIC,KACnBA,EAAO,KAAIC,aACXA,EAAe,KAAIC,KACnBA,EAAO,KAAIpB,cACXA,EAAgB,KAAIC,aACpBA,EAAe,SAAQoB,WACvBA,EAAa,OAEbnB,KAAKe,aAAeA,EACpBf,KAAKiB,aAAeA,EACpBjB,KAAKgB,KAAOA,EACZhB,KAAKkB,KAAOA,EACZlB,KAAKF,cAAgBA,EACrBE,KAAKD,aAAeA,EACpBC,KAAKmB,WAAaA,EAElBnB,KAAKoB,2BAA4B,EAE7BpB,KAAKmB,aACPzE,EAAS,mEACTsD,KAAKqB,oBAER,CAKD,iBAAAA,GAKE,GAJKrB,KAAKmB,WAAWG,gBACnB3E,EAAS,sDAIiC,iBAAnCqD,KAAKmB,WAAWG,iBACtBjD,MAAMkD,QAAQvB,KAAKmB,WAAWG,gBAC/B,CAEA,MAAME,EAAexB,KAAKmB,WAAWG,eAAeE,cAAgB,GASpE,GARyBxB,KAAKmB,WAAWG,eAAeG,iBAExDnF,EACE,yDACEoF,KAAKC,UAAU3B,KAAKmB,WAAWG,iBAI/BtB,KAAKmB,WAAWS,aAAa,IAAM5B,KAAKmB,WAAWS,aAAa,IAAK,CAEvE,MAAMC,EAAuB,GAE7B,IAAK,IAAIC,EAAU,EAAGA,EAAUN,EAAatF,OAAQ4F,IAAW,CAC9D,MAAMC,EAAYP,EAAaM,GACzBE,EAAiB,IAAI3D,MAAM0D,EAAU7F,QAGlB,IAArB6F,EAAU7F,QAOZ8F,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,IACA,IAArBA,EAAU7F,SASnB8F,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,IAGhCF,EAAqBI,KAAKD,EAC3B,CAEDhC,KAAKmB,WAAWG,eAAiBO,CAClC,MAAU7B,KAAKmB,WAAWS,aAAa,IACtCjF,EAAS,4FASX,GANAL,EACE,gEACEoF,KAAKC,UAAU3B,KAAKmB,WAAWG,iBAI/BtB,KAAKmB,WAAWe,iBAAmBlC,KAAKmB,WAAWgB,iBAAkB,CAEvE,GACE9D,MAAMkD,QAAQvB,KAAKmB,WAAWgB,mBAC9BnC,KAAKmB,WAAWgB,iBAAiBjG,OAAS,QACFkG,IAAxCpC,KAAKmB,WAAWgB,iBAAiB,GACjC,CAEA,MAAME,EAAwB,GAC9B,IAAK,IAAIpG,EAAI,EAAGA,EAAI+D,KAAKmB,WAAWgB,iBAAiBjG,OAAQD,IACvD+D,KAAKmB,WAAWgB,iBAAiBlG,IACnCoG,EAAsBJ,KAAKjC,KAAKmB,WAAWgB,iBAAiBlG,IAGhE+D,KAAKmB,WAAWgB,iBAAmBE,CACpC,CAGD,GAAIrC,KAAKmB,WAAWmB,oBAAsBtC,KAAKmB,WAAWC,4BAExDpB,KAAKmB,WAAWgB,iBAAmB,GAGnCnC,KAAKmB,WAAWe,gBAAgBK,SAASC,IAEvC,GAAuB,IAAnBA,EAAKC,UAAiB,CAExB,MAAMH,EAAoBtC,KAAKmB,WAAWmB,kBAAkBE,EAAKE,MAAQ,GAErEJ,EAAkBpG,OAAS,IAExB8D,KAAKmB,WAAWgB,iBAAiBK,EAAKE,OACzC1C,KAAKmB,WAAWgB,iBAAiBK,EAAKE,KAAO,IAI/CJ,EAAkBC,SAASI,IACzB,MAAMC,EAAQD,EAAU,GAClBE,EAAQF,EAAU,GAExBrG,EACE,mCAAmCsG,MAAUC,mBAAuBL,EAAKE,QACvEF,EAAKM,MAAQ,cAKjB,IAAIC,GAAe,EAGnB,IAAK,IAAIjB,EAAU,EAAGA,EAAU9B,KAAKmB,WAAWG,eAAepF,OAAQ4F,IAAW,CAChF,MAAMkB,EAAYhD,KAAKmB,WAAWG,eAAeQ,GAGjD,GAAyB,IAArBkB,EAAU9G,QAEZ,GAAI8G,EAAUC,SAASL,IAAUI,EAAUC,SAASJ,GAAQ,CAE1D,IAAIK,EAEJ,MAAMC,EAAaH,EAAUI,QAAQR,GAC/BS,EAAaL,EAAUI,QAAQP,GAErCvG,EACE,mBAAmBwF,gDAAsDkB,EAAUM,KACjF,UAGJhH,EACE,UAAUsG,iBAAqBO,WAAoBN,iBAAqBQ,oBASxD,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBH,EAAO,EACP5G,EAAS,uCAAuC4G,iBAAoBpB,MAEpD,IAAfqB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBH,EAAO,EACP5G,EAAS,qCAAqC4G,iBAAoBpB,MAElD,IAAfqB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBH,EAAO,EACP5G,EAAS,oCAAoC4G,iBAAoBpB,OAEjD,IAAfqB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,KAErBH,EAAO,EACP5G,EAAS,sCAAsC4G,iBAAoBpB,MAIrE9B,KAAKmB,WAAWgB,iBAAiBK,EAAKE,KAAKT,KAAK,CAACH,EAASoB,IAC1D5G,EACE,8BAA8BwF,MAAYoB,sBAAyBV,EAAKE,OAE1EK,GAAe,EACf,KACD,OACI,GAAyB,IAArBC,EAAU9G,QAGf8G,EAAUC,SAASL,IAAUI,EAAUC,SAASJ,GAAQ,CAE1D,IAAIK,EAEJ,MAAMC,EAAaH,EAAUI,QAAQR,GAC/BS,EAAaL,EAAUI,QAAQP,GAErCvG,EACE,mBAAmBwF,gDAAsDkB,EAAUM,KACjF,UAGJhH,EACE,UAAUsG,iBAAqBO,WAAoBN,iBAAqBQ,oBAYxD,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBH,EAAO,EACP5G,EAAS,uCAAuC4G,iBAAoBpB,MAEpD,IAAfqB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBH,EAAO,EACP5G,EAAS,qCAAqC4G,iBAAoBpB,MAElD,IAAfqB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBH,EAAO,EACP5G,EAAS,oCAAoC4G,iBAAoBpB,OAEjD,IAAfqB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,KAErBH,EAAO,EACP5G,EAAS,sCAAsC4G,iBAAoBpB,MAIrE9B,KAAKmB,WAAWgB,iBAAiBK,EAAKE,KAAKT,KAAK,CAACH,EAASoB,IAC1D5G,EACE,8BAA8BwF,MAAYoB,sBAAyBV,EAAKE,OAE1EK,GAAe,EACf,KACD,CAEJ,CAEIA,GACHpG,EACE,oDAAoDiG,SAAaC,iCAEpE,IAGN,KAIH7C,KAAKoB,2BAA4B,EAI/BpB,KAAKmB,WAAWgB,iBAAiBjG,OAAS,QACFkG,IAAxCpC,KAAKmB,WAAWgB,iBAAiB,IACjC,CACA,MAAME,EAAwB,GAC9B,IAAK,IAAIpG,EAAI,EAAGA,EAAI+D,KAAKmB,WAAWgB,iBAAiBjG,OAAQD,IACvD+D,KAAKmB,WAAWgB,iBAAiBlG,IACnCoG,EAAsBJ,KAAKjC,KAAKmB,WAAWgB,iBAAiBlG,IAGhE+D,KAAKmB,WAAWgB,iBAAmBE,CACpC,CAEJ,CACF,CAED,OAAOrC,KAAKmB,UACb,EAGI,MAAMoC,UAAezC,EAS1B,WAAAjB,EAAYkB,aAAEA,EAAe,KAAIC,KAAEA,EAAO,KAAIjB,aAAEA,EAAe,SAAQoB,WAAEA,EAAa,OACpFqC,MAAM,CACJzC,eACAC,OACAC,aAAc,EACdC,KAAM,EACNpB,cAAe,KACfC,eACAoB,eAGwB,OAAtBnB,KAAKe,cAAuC,OAAdf,KAAKgB,MACrCrE,EAAS,wFAEZ,CAED,YAAA8G,GACE,IAAInE,EAAoB,GAGxB,IAAIoE,EAAavE,EAEjB,GAA0B,WAAtBa,KAAKD,aAA2B,CAClC2D,EAAc1D,KAAKe,aAAe,EAClC5B,GAAUa,KAAKgB,KALF,GAKmBhB,KAAKe,aAErCzB,EAAkB,GAPL,EAQb,IAAK,IAAIqE,EAAY,EAAGA,EAAYD,EAAaC,IAC/CrE,EAAkBqE,GAAarE,EAAkBqE,EAAY,GAAKxE,CAE1E,MAAW,GAA0B,cAAtBa,KAAKD,aAA8B,CAC5C2D,EAAc,EAAI1D,KAAKe,aAAe,EACtC5B,GAAUa,KAAKgB,KAbF,GAamBhB,KAAKe,aAErCzB,EAAkB,GAfL,EAgBb,IAAK,IAAIqE,EAAY,EAAGA,EAAYD,EAAaC,IAC/CrE,EAAkBqE,GAAarE,EAAkBqE,EAAY,GAAKxE,EAAS,CAE9E,CAED,MAAMmC,EAAiBtB,KAAK4D,yBAAyB5D,KAAKe,aAAc2C,EAAa1D,KAAKD,cAEpFoC,EAAmBnC,KAAK6D,uBAK9B,OAHAvH,EAAS,iCAAmCoF,KAAKC,UAAUrC,IAGpD,CACLA,oBACAoE,cACApC,iBACAa,mBAEH,CAUD,wBAAAyB,CAAyB7C,EAAc2C,EAAa3D,GAKlD,IAAI+D,EAAM,GAEV,GAAqB,WAAjB/D,EAOF,IAAK,IAAIgE,EAAe,EAAGA,EAAehD,EAAcgD,IAAgB,CACtED,EAAIC,GAAgB,GACpB,IAAK,IAAIJ,EAAY,EAAGA,GAAa,EAAGA,IACtCG,EAAIC,GAAcJ,EAAY,GAAKI,EAAeJ,CAErD,MACI,GAAqB,cAAjB5D,EAA8B,CAOvC,IAAIiE,EAAgB,EACpB,IAAK,IAAID,EAAe,EAAGA,EAAehD,EAAcgD,IAAgB,CACtED,EAAIC,GAAgB,GACpB,IAAK,IAAIJ,EAAY,EAAGA,GAAa,EAAGA,IACtCG,EAAIC,GAAcJ,EAAY,GAAKI,EAAeJ,EAAYK,EAEhEA,GAAiB,CAClB,CACF,CAED,OAAOF,CACR,CAYD,oBAAAD,GACE,MAAM1B,EAAmB,GAEzB,IAAK,IAAI8B,EAAY,EAAGA,EADP,EAC6BA,IAC5C9B,EAAiBF,KAAK,IAWxB,OAPAE,EAAiB,GAAGF,KAAK,CAAC,EAAG,IAG7BE,EAAiB,GAAGF,KAAK,CAACjC,KAAKe,aAAe,EAAG,IAEjDzE,EAAS,yCAA2CoF,KAAKC,UAAUQ,IACnEnC,KAAKoB,2BAA4B,EAC1Be,CACR,EAGI,MAAM+B,UAAepD,EAW1B,WAAAjB,EAAYkB,aACVA,EAAe,KAAIC,KACnBA,EAAO,KAAIC,aACXA,EAAe,KAAIC,KACnBA,EAAO,KAAInB,aACXA,EAAe,SAAQoB,WACvBA,EAAa,OAEbqC,MAAM,CACJzC,eACAC,OACAC,eACAC,OACApB,cAAe,KACfC,eACAoB,eAKCA,GACsB,OAAtBnB,KAAKe,cAAuC,OAAdf,KAAKgB,MAAuC,OAAtBhB,KAAKiB,cAAuC,OAAdjB,KAAKkB,MAExFvE,EACE,6GAGL,CAED,YAAA8G,GACE,IAAInE,EAAoB,GACpB6E,EAAoB,GAGxB,IAAIT,EAAaU,EAAajF,EAAQkF,EAEtC,GAA0B,WAAtBrE,KAAKD,aAA2B,CAClC2D,EAAc1D,KAAKe,aAAe,EAClCqD,EAAcpE,KAAKiB,aAAe,EAClC9B,GAAUa,KAAKgB,KAPF,GAOmBhB,KAAKe,aACrCsD,GAAUrE,KAAKkB,KAPF,GAOmBlB,KAAKiB,aAErC3B,EAAkB,GAVL,EAWb6E,EAAkB,GAVL,EAWb,IAAK,IAAIG,EAAa,EAAGA,EAAaF,EAAaE,IACjDhF,EAAkBgF,GAAchF,EAAkB,GAClD6E,EAAkBG,GAAcH,EAAkB,GAAKG,EAAaD,EAEtE,IAAK,IAAIE,EAAa,EAAGA,EAAab,EAAaa,IAAc,CAC/D,MAAMC,EAAQD,EAAaH,EAC3B9E,EAAkBkF,GAASlF,EAAkB,GAAKiF,EAAapF,EAC/DgF,EAAkBK,GAASL,EAAkB,GAC7C,IAAK,IAAIG,EAAa,EAAGA,EAAaF,EAAaE,IACjDhF,EAAkBkF,EAAQF,GAAchF,EAAkBkF,GAC1DL,EAAkBK,EAAQF,GAAcH,EAAkBK,GAASF,EAAaD,CAEnF,CACP,MAAW,GAA0B,cAAtBrE,KAAKD,aAA8B,CAC5C2D,EAAc,EAAI1D,KAAKe,aAAe,EACtCqD,EAAc,EAAIpE,KAAKiB,aAAe,EACtC9B,GAAUa,KAAKgB,KA5BF,GA4BmBhB,KAAKe,aACrCsD,GAAUrE,KAAKkB,KA5BF,GA4BmBlB,KAAKiB,aAErC3B,EAAkB,GA/BL,EAgCb6E,EAAkB,GA/BL,EAgCb,IAAK,IAAIG,EAAa,EAAGA,EAAaF,EAAaE,IACjDhF,EAAkBgF,GAAchF,EAAkB,GAClD6E,EAAkBG,GAAcH,EAAkB,GAAMG,EAAaD,EAAU,EAEjF,IAAK,IAAIE,EAAa,EAAGA,EAAab,EAAaa,IAAc,CAC/D,MAAMC,EAAQD,EAAaH,EAC3B9E,EAAkBkF,GAASlF,EAAkB,GAAMiF,EAAapF,EAAU,EAC1EgF,EAAkBK,GAASL,EAAkB,GAC7C,IAAK,IAAIG,EAAa,EAAGA,EAAaF,EAAaE,IACjDhF,EAAkBkF,EAAQF,GAAchF,EAAkBkF,GAC1DL,EAAkBK,EAAQF,GAAcH,EAAkBK,GAAUF,EAAaD,EAAU,CAE9F,CACF,CAGD,MAAM/C,EAAiBtB,KAAKyE,yBAC1BzE,KAAKe,aACLf,KAAKiB,aACLmD,EACApE,KAAKD,cAIDoC,EAAmBnC,KAAK6D,uBAM9B,OAJAvH,EAAS,iCAAmCoF,KAAKC,UAAUrC,IAC3DhD,EAAS,iCAAmCoF,KAAKC,UAAUwC,IAGpD,CACL7E,oBACA6E,oBACAT,cACAU,cACA9C,iBACAa,mBAEH,CAYD,wBAAAsC,CAAyB1D,EAAcE,EAAcmD,EAAarE,GAChE,IAAIgE,EAAe,EACfD,EAAM,GAEV,GAAqB,WAAjB/D,EAA2B,CAS7B,IAAI2E,EAAa,EACbV,EAAgB,EACpB,IAAK,IAAID,EAAe,EAAGA,EAAehD,EAAeE,EAAc8C,IACrEW,GAAc,EACdZ,EAAIC,GAAgB,GACpBD,EAAIC,GAAc,GAAKA,EAAeC,EAAgB,EACtDF,EAAIC,GAAc,GAAKA,EAAeC,EACtCF,EAAIC,GAAc,GAAKA,EAAeC,EAAgB/C,EACtD6C,EAAIC,GAAc,GAAKA,EAAeC,EAAgB/C,EAAe,EACjEyD,IAAezD,IACjB+C,GAAiB,EACjBU,EAAa,EAGvB,MAAW,GAAqB,cAAjB3E,EAWT,IAAK,IAAI4E,EAAgB,EAAGA,GAAiB5D,EAAc4D,IACzD,IAAK,IAAIC,EAAgB,EAAGA,GAAiB3D,EAAc2D,IAAiB,CAC1Ed,EAAIC,GAAgB,GACpB,IAAK,IAAIc,EAAa,EAAGA,GAAc,EAAGA,IAAc,CACtD,IAAIC,EAAa,EAAID,EAAa,EAClCf,EAAIC,GAAce,EAAa,GAC7BV,GAAe,EAAIO,EAAgBE,EAAa,GAAK,EAAID,EAAgB,EAC3Ed,EAAIC,GAAce,GAAchB,EAAIC,GAAce,EAAa,GAAK,EACpEhB,EAAIC,GAAce,EAAa,GAAKhB,EAAIC,GAAce,EAAa,GAAK,CACzE,CACDf,GAA8B,CAC/B,CAIL,OAAOD,CACR,CAcD,oBAAAD,GACE,MAAM1B,EAAmB,GAGzB,IAAK,IAAI8B,EAAY,EAAGA,EAFP,EAE6BA,IAC5C9B,EAAiBF,KAAK,IAMxB,IAAK,IAAI0C,EAAgB,EAAGA,EAAgB3E,KAAKe,aAAc4D,IAC7D,IAAK,IAAIC,EAAgB,EAAGA,EAAgB5E,KAAKiB,aAAc2D,IAAiB,CAC9E,MAAMb,EAAeY,EAAgB3E,KAAKiB,aAAe2D,EAGnC,IAAlBA,GACFzC,EAAiB,GAAGF,KAAK,CAAC8B,EAAc,IAIpB,IAAlBY,GACFxC,EAAiB,GAAGF,KAAK,CAAC8B,EAAc,IAItCa,IAAkB5E,KAAKiB,aAAe,GACxCkB,EAAiB,GAAGF,KAAK,CAAC8B,EAAc,IAItCY,IAAkB3E,KAAKe,aAAe,GACxCoB,EAAiB,GAAGF,KAAK,CAAC8B,EAAc,GAE3C,CAKH,OAFAzH,EAAS,yCAA2CoF,KAAKC,UAAUQ,IACnEnC,KAAKoB,2BAA4B,EAC1Be,CACR,EC5sBI,MAAM4C,EAMX,WAAAlF,EAAYC,cAAEA,EAAaC,aAAEA,IAC3BC,KAAKF,cAAgBA,EACrBE,KAAKD,aAAeA,CACrB,CAQD,wBAAAiF,GACE,IAAIC,EAAc,GACdC,EAAe,GAgBnB,MAd0B,WAAtBlF,KAAKD,cAEPkF,EAAY,GAAK,GACjBC,EAAa,GAAK,GACa,cAAtBlF,KAAKD,eAEdkF,EAAY,IAAM,EAAI9I,KAAKC,KAAK,KAAU,EAC1C6I,EAAY,GAAK,GACjBA,EAAY,IAAM,EAAI9I,KAAKC,KAAK,KAAU,EAC1C8I,EAAa,GAAK,EAAI,GACtBA,EAAa,GAAK,EAAI,GACtBA,EAAa,GAAK,EAAI,IAGjB,CAAED,cAAaC,eACvB,EC+BI,SAASC,EAAc9F,GAC5B,MAAMD,WAAEA,EAAU0E,IAAEA,EAAGhE,cAAEA,EAAaC,aAAEA,GAAiBV,EAGzD,IAAItC,EAAiB,GACjBD,EAAiB,GAIrB,IAAK,IAAI6G,EAAY,EAAGA,EAAYvE,EAAYuE,IAAa,CAC3D5G,EAAe4G,GAAa,EAC5B7G,EAAemF,KAAK,IACpB,IAAK,IAAImD,EAAW,EAAGA,EAAWhG,EAAYgG,IAC5CtI,EAAe6G,GAAWyB,GAAY,CAEzC,CAGD,MAAMC,EAAiB,IAAIzF,EAAe,CACxCE,gBACAC,iBAUF,IAAIuF,EANyB,IAAIP,EAAqB,CACpDjF,gBACAC,iBAI+CiF,2BAOjD,MAAO,CACLjI,iBACAD,iBACAyI,iBAlCqB,GAmCrBF,iBACAJ,YAXgBK,EAAsBL,YAYtCC,aAXiBI,EAAsBJ,aAYvCM,SATe1B,EAAI,GAAG5H,OAW1B,CAOO,SAASuJ,EAA8BC,GAC5C,MAAMtF,cAAEA,EAAaC,sBAAEA,EAAqBf,kBAAEA,EAAiBiG,iBAAEA,EAAgBC,SAAEA,GAAaE,EAEhG,IAAIC,EAAe,EACfC,EAAY,EAGhB,IAAK,IAAIC,EAAiB,EAAGA,EAAiBL,EAAUK,IACtDF,GAAgBrG,EAAkBiG,EAAiBM,IAAmBzF,EAAcyF,GACpFD,GAAatG,EAAkBiG,EAAiBM,IAAmBxF,EAAsBwF,GAE3F,IAAIC,EAAcF,EAGdG,EAAsB,GAC1B,IAAK,IAAIF,EAAiB,EAAGA,EAAiBL,EAAUK,IACtDE,EAAoBF,GAAkBxF,EAAsBwF,GAAkBC,EAGhF,MAAO,CACLH,eACAG,cACAC,sBAEJ,CAOO,SAASC,EAA8BN,GAC5C,MAAMtF,cACJA,EAAaC,sBACbA,EAAqBC,sBACrBA,EAAqBhB,kBACrBA,EAAiB6E,kBACjBA,EAAiBoB,iBACjBA,EAAgBC,SAChBA,GACEE,EAEJ,IAAIC,EAAe,EACfM,EAAe,EACfL,EAAY,EACZM,EAAY,EACZC,EAAY,EACZC,EAAY,EAGhB,IAAK,IAAIP,EAAiB,EAAGA,EAAiBL,EAAUK,IACtDF,GAAgBrG,EAAkBiG,EAAiBM,IAAmBzF,EAAcyF,GACpFI,GAAgB9B,EAAkBoB,EAAiBM,IAAmBzF,EAAcyF,GACpFD,GAAatG,EAAkBiG,EAAiBM,IAAmBxF,EAAsBwF,GACzFK,GAAa5G,EAAkBiG,EAAiBM,IAAmBvF,EAAsBuF,GACzFM,GAAahC,EAAkBoB,EAAiBM,IAAmBxF,EAAsBwF,GACzFO,GAAajC,EAAkBoB,EAAiBM,IAAmBvF,EAAsBuF,GAE3F,IAAIC,EAAcF,EAAYQ,EAAYF,EAAYC,EAGlDJ,EAAsB,GACtBM,EAAsB,GAC1B,IAAK,IAAIR,EAAiB,EAAGA,EAAiBL,EAAUK,IAEtDE,EAAoBF,IACjBO,EAAY/F,EAAsBwF,GACjCM,EAAY7F,EAAsBuF,IACpCC,EAEFO,EAAoBR,IACjBD,EAAYtF,EAAsBuF,GACjCK,EAAY7F,EAAsBwF,IACpCC,EAGJ,MAAO,CACLH,eACAM,eACAH,cACAC,sBACAM,sBAEJ,CCrMO,MAAMC,EASX,WAAAzG,CAAYJ,EAAoB0C,EAAkB2B,EAAKhE,EAAeC,GACpEC,KAAKP,mBAAqBA,EAC1BO,KAAKmC,iBAAmBA,EACxBnC,KAAK8D,IAAMA,EACX9D,KAAKF,cAAgBA,EACrBE,KAAKD,aAAeA,CACrB,CAOD,qCAAAwG,CAAsCxJ,EAAgBD,GACpDJ,EAAS,+CACkB,OAAvBsD,KAAKF,cACP0G,OAAOC,KAAKzG,KAAKP,oBAAoB8C,SAASmE,IAC5C,GAAgD,kBAA5C1G,KAAKP,mBAAmBiH,GAAa,GAAwB,CAC/D,MAAMC,EAAQ3G,KAAKP,mBAAmBiH,GAAa,GACnDpK,EAAS,YAAYoK,iCAA2CC,2BAChE3G,KAAKmC,iBAAiBuE,GAAanE,SAAQ,EAAEwB,EAAcb,MACzD,GAA0B,WAAtBlD,KAAKD,aAA2B,EACZ,CACpB,EAAG,CAAC,GACJ,EAAG,CAAC,KAEQmD,GAAMX,SAASoB,IAC3B,MAAMiD,EAAkB5G,KAAK8D,IAAIC,GAAcJ,GAAa,EAC5DrH,EACE,sCAAsCsK,EAAkB,cACtD7C,EAAe,iBACDJ,EAAY,MAG9B5G,EAAe6J,GAAmBD,EAElC,IAAK,IAAIvB,EAAW,EAAGA,EAAWrI,EAAeb,OAAQkJ,IACvDtI,EAAe8J,GAAiBxB,GAAY,EAG9CtI,EAAe8J,GAAiBA,GAAmB,CAAC,GAEpE,MAAmB,GAA0B,cAAtB5G,KAAKD,aAA8B,EACtB,CACpB,EAAG,CAAC,GACJ,EAAG,CAAC,KAEQmD,GAAMX,SAASoB,IAC3B,MAAMiD,EAAkB5G,KAAK8D,IAAIC,GAAcJ,GAAa,EAC5DrH,EACE,sCAAsCsK,EAAkB,cACtD7C,EAAe,iBACDJ,EAAY,MAG9B5G,EAAe6J,GAAmBD,EAElC,IAAK,IAAIvB,EAAW,EAAGA,EAAWrI,EAAeb,OAAQkJ,IACvDtI,EAAe8J,GAAiBxB,GAAY,EAG9CtI,EAAe8J,GAAiBA,GAAmB,CAAC,GAEvD,IAEJ,KAE6B,OAAvB5G,KAAKF,eACd0G,OAAOC,KAAKzG,KAAKP,oBAAoB8C,SAASmE,IAC5C,GAAgD,kBAA5C1G,KAAKP,mBAAmBiH,GAAa,GAAwB,CAC/D,MAAMC,EAAQ3G,KAAKP,mBAAmBiH,GAAa,GACnDpK,EAAS,YAAYoK,iCAA2CC,2BAChE3G,KAAKmC,iBAAiBuE,GAAanE,SAAQ,EAAEwB,EAAcb,MACzD,GAA0B,WAAtBlD,KAAKD,aAA2B,EACZ,CACpB,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,KAEKmD,GAAMX,SAASoB,IAC3B,MAAMiD,EAAkB5G,KAAK8D,IAAIC,GAAcJ,GAAa,EAC5DrH,EACE,sCAAsCsK,EAAkB,cACtD7C,EAAe,iBACDJ,EAAY,MAG9B5G,EAAe6J,GAAmBD,EAElC,IAAK,IAAIvB,EAAW,EAAGA,EAAWrI,EAAeb,OAAQkJ,IACvDtI,EAAe8J,GAAiBxB,GAAY,EAG9CtI,EAAe8J,GAAiBA,GAAmB,CAAC,GAEpE,MAAmB,GAA0B,cAAtB5G,KAAKD,aAA8B,EACtB,CACpB,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,KAEEmD,GAAMX,SAASoB,IAC3B,MAAMiD,EAAkB5G,KAAK8D,IAAIC,GAAcJ,GAAa,EAC5DrH,EACE,sCAAsCsK,EAAkB,cACtD7C,EAAe,iBACDJ,EAAY,MAG9B5G,EAAe6J,GAAmBD,EAElC,IAAK,IAAIvB,EAAW,EAAGA,EAAWrI,EAAeb,OAAQkJ,IACvDtI,EAAe8J,GAAiBxB,GAAY,EAG9CtI,EAAe8J,GAAiBA,GAAmB,CAAC,GAEvD,IAEJ,IAGN,EC3HI,SAASC,EACdxH,EACAI,EACAtC,EACAuC,GAEAhD,EAAS,iDAIT,IAAIoK,EAAqB,EAAIpH,EADE,IAE/BhD,EAAS,uBAAuBoK,KAChCpK,EAAS,0BAA0BgD,KAGnC,MAAMJ,kBACJA,EAAiB6E,kBACjBA,EAAiBL,IACjBA,EAAG3B,iBACHA,EAAgB4E,cAChBA,EAAajH,cACbA,EAAaC,aACbA,GACEV,EAGE2H,EAAU7B,EAAc9F,IACxBtC,eACJA,EAAcD,eACdA,EAAcyI,iBACdA,EAAgBF,eAChBA,EAAcJ,YACdA,EAAWC,aACXA,EAAYM,SACZA,GACEwB,EAGJ,IAAK,IAAIjD,EAAe,EAAGA,EAAegD,EAAehD,IAAgB,CAEvE,IAAK,IAAI8B,EAAiB,EAAGA,EAAiBL,EAAUK,IAEtDN,EAAiBM,GAAkB/B,EAAIC,GAAc8B,GAAkB,EAIzE,IAAK,IAAIoB,EAAmB,EAAGA,EAAmBhC,EAAY/I,OAAQ+K,IAEpE,GAAsB,OAAlBnH,EAAwB,CAE1B,IAAIoH,EAA+B7B,EAAepF,kBAAkBgF,EAAYgC,IAGhF,MAAME,EAAgB1B,EAA8B,CAClDrF,cAAe8G,EAA6B9G,cAC5CC,sBAAuB6G,EAA6B7G,sBACpDf,oBACAiG,mBACAC,cAIIM,YAAEA,EAAWC,oBAAEA,GAAwBoB,EACvBD,EAA6B9G,cAGnD,IAAIgH,EAAiB,EACrB,IAAK,IAAIvB,EAAiB,EAAGA,EAAiBL,EAAUK,IACtDuB,GACEjK,EAAeoI,EAAiBM,IAAmBE,EAAoBF,GAI3E,IAAK,IAAIwB,EAAkB,EAAGA,EAAkB7B,EAAU6B,IAAmB,CACnD9B,EAAiB8B,GAIzC,IAAK,IAAIC,EAAkB,EAAGA,EAAkB9B,EAAU8B,IAChC/B,EAAiB+B,EAI5C,CACF,MAEI,GAAsB,OAAlBxH,EACP,IAAK,IAAIyH,EAAmB,EAAGA,EAAmBtC,EAAY/I,OAAQqL,IAAoB,CAExF,IAAIL,EAA+B7B,EAAepF,kBAChDgF,EAAYgC,GACZhC,EAAYsC,IAId,MAAMJ,EAAgBnB,EAA8B,CAClD5F,cAAe8G,EAA6B9G,cAC5CC,sBAAuB6G,EAA6B7G,sBACpDC,sBAAuB4G,EAA6B5G,sBACpDhB,oBACA6E,oBACAoB,mBACAC,cAIIM,YAAEA,EAAWC,oBAAEA,EAAmBM,oBAAEA,GAAwBc,EAC5D/G,EAAgB8G,EAA6B9G,cAGnD,IAAIgH,EAAiB,EACjBI,EAAiB,EACrB,IAAK,IAAI3B,EAAiB,EAAGA,EAAiBL,EAAUK,IACtDuB,GACEjK,EAAeoI,EAAiBM,IAAmBE,EAAoBF,GACzE2B,GACErK,EAAeoI,EAAiBM,IAAmBQ,EAAoBR,GAI3E,IAAK,IAAIwB,EAAkB,EAAGA,EAAkB7B,EAAU6B,IAAmB,CAC3E,IAAII,EAAoBlC,EAAiB8B,GAGzCtK,EAAe0K,IACbX,EACE5B,EAAa+B,GACb/B,EAAaqC,GACbzB,EACAC,EAAoBsB,GACpBD,EACFN,EACE5B,EAAa+B,GACb/B,EAAaqC,GACbzB,EACAO,EAAoBgB,GACpBG,EAG0B,IAA1B9H,IACF3C,EAAe0K,IACb/H,GACCwF,EAAa+B,GACZ/B,EAAaqC,GACbzB,EACA1F,EAAciH,GACdlL,KAAKC,KAAKgL,GAAkB,EAAII,GAAkB,GAClDtC,EAAa+B,GACX/B,EAAaqC,GACbzB,EACA1F,EAAciH,KAGtB,IAAK,IAAIC,EAAkB,EAAGA,EAAkB9B,EAAU8B,IAAmB,CAC3E,IAAII,EAAoBnC,EAAiB+B,GAGzCxK,EAAe2K,GAAmBC,KAC/BZ,EACD5B,EAAa+B,GACb/B,EAAaqC,GACbzB,GACCC,EAAoBsB,GAAmBtB,EAAoBuB,GAC1DjB,EAAoBgB,GAAmBhB,EAAoBiB,IAGjC,IAA1B5H,IACF5C,EAAe2K,GAAmBC,IAChChI,IAEIoG,EACAsB,EACAhH,EAAciH,GACdnC,EAAa+B,GACb/B,EAAaqC,GAEbpL,KAAKC,KAAKgL,GAAkB,EAAII,GAAkB,EAAI,OACxDzB,EAAoBuB,GACpBxB,EACA0B,EACApH,EAAciH,GACdnC,EAAa+B,GACb/B,EAAaqC,GACbpL,KAAKC,KAAKgL,GAAkB,EAAII,GAAkB,EAAI,MACtDnB,EAAoBiB,GAE3B,CACF,CACF,CAGN,CAGD5K,EAAS,2CACyB,IAAI4J,EACpC7G,EACA0C,EACA2B,EACAhE,EACAC,GAIwBwG,sCAAsCxJ,EAAgBD,GAChFJ,EAAS,8CAGTJ,EAAS,2BACT,IAAK,IAAIL,EAAI,EAAGA,EAAIc,EAAeb,OAAQD,IACzCK,EAAS,QAAQL,MAAMc,EAAed,GAAG0D,cAAc,MAKzD,OAFAjD,EAAS,+CAEF,CACLI,iBACAC,iBAEJ,CCxOO,MAAM4K,EASX,WAAA9H,CAAYJ,EAAoB0C,EAAkB2B,EAAKhE,EAAeC,GACpEC,KAAKP,mBAAqBA,EAC1BO,KAAKmC,iBAAmBA,EACxBnC,KAAK8D,IAAMA,EACX9D,KAAKF,cAAgBA,EACrBE,KAAKD,aAAeA,CACrB,CAOD,oCAAA6H,CAAqC7K,EAAgBD,GACnDJ,EAAS,qDACkB,OAAvBsD,KAAKF,cACP0G,OAAOC,KAAKzG,KAAKP,oBAAoB8C,SAASmE,IAC5C,GAAgD,iBAA5C1G,KAAKP,mBAAmBiH,GAAa,GAAuB,CAC9D,MAAMmB,EAAY7H,KAAKP,mBAAmBiH,GAAa,GACvDpK,EACE,YAAYoK,uCAAiDmB,6BAE/D7H,KAAKmC,iBAAiBuE,GAAanE,SAAQ,EAAEwB,EAAcb,MACzD,GAA0B,WAAtBlD,KAAKD,aAA2B,EACZ,CACpB,EAAG,CAAC,GACJ,EAAG,CAAC,KAEQmD,GAAMX,SAASoB,IAC3B,MAAMiD,EAAkB5G,KAAK8D,IAAIC,GAAcJ,GAAa,EAC5DrH,EACE,4CAA4CsK,EAAkB,cAC5D7C,EAAe,iBACDJ,EAAY,MAG9B5G,EAAe6J,GAAmBiB,EAElC,IAAK,IAAIzC,EAAW,EAAGA,EAAWrI,EAAeb,OAAQkJ,IACvDtI,EAAe8J,GAAiBxB,GAAY,EAG9CtI,EAAe8J,GAAiBA,GAAmB,CAAC,GAEpE,MAAmB,GAA0B,cAAtB5G,KAAKD,aAA8B,EACtB,CACpB,EAAG,CAAC,GACJ,EAAG,CAAC,KAEQmD,GAAMX,SAASoB,IAC3B,MAAMiD,EAAkB5G,KAAK8D,IAAIC,GAAcJ,GAAa,EAC5DrH,EACE,4CAA4CsK,EAAkB,cAC5D7C,EAAe,iBACDJ,EAAY,MAG9B5G,EAAe6J,GAAmBiB,EAElC,IAAK,IAAIzC,EAAW,EAAGA,EAAWrI,EAAeb,OAAQkJ,IACvDtI,EAAe8J,GAAiBxB,GAAY,EAG9CtI,EAAe8J,GAAiBA,GAAmB,CAAC,GAEvD,IAEJ,KAE6B,OAAvB5G,KAAKF,eACd0G,OAAOC,KAAKzG,KAAKP,oBAAoB8C,SAASmE,IAC5C,GAAgD,iBAA5C1G,KAAKP,mBAAmBiH,GAAa,GAAuB,CAC9D,MAAMmB,EAAY7H,KAAKP,mBAAmBiH,GAAa,GACvDpK,EACE,YAAYoK,uCAAiDmB,6BAE/D7H,KAAKmC,iBAAiBuE,GAAanE,SAAQ,EAAEwB,EAAcb,MACzD,GAA0B,WAAtBlD,KAAKD,aAA2B,EACZ,CACpB,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,KAEKmD,GAAMX,SAASoB,IAC3B,MAAMiD,EAAkB5G,KAAK8D,IAAIC,GAAcJ,GAAa,EAC5DrH,EACE,4CAA4CsK,EAAkB,cAC5D7C,EAAe,iBACDJ,EAAY,MAG9B5G,EAAe6J,GAAmBiB,EAElC,IAAK,IAAIzC,EAAW,EAAGA,EAAWrI,EAAeb,OAAQkJ,IACvDtI,EAAe8J,GAAiBxB,GAAY,EAG9CtI,EAAe8J,GAAiBA,GAAmB,CAAC,GAEpE,MAAmB,GAA0B,cAAtB5G,KAAKD,aAA8B,EACtB,CACpB,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,KAEEmD,GAAMX,SAASoB,IAC3B,MAAMiD,EAAkB5G,KAAK8D,IAAIC,GAAcJ,GAAa,EAC5DrH,EACE,4CAA4CsK,EAAkB,cAC5D7C,EAAe,iBACDJ,EAAY,MAG9B5G,EAAe6J,GAAmBiB,EAElC,IAAK,IAAIzC,EAAW,EAAGA,EAAWrI,EAAeb,OAAQkJ,IACvDtI,EAAe8J,GAAiBxB,GAAY,EAG9CtI,EAAe8J,GAAiBA,GAAmB,CAAC,GAEvD,IAEJ,IAGN,CAYD,kCAAAkB,CACE/K,EACAD,EACAmI,EACAC,EACA5F,EACA6E,EACAkB,GAEA3I,EAAS,2CAET,IAAIqL,EAA2B,GAC3BC,EAAoB,GACxBxB,OAAOC,KAAKzG,KAAKP,oBAAoB8C,SAAS0F,IAC5C,MAAMC,EAAoBlI,KAAKP,mBAAmBwI,GACrB,eAAzBC,EAAkB,KACpBH,EAAyBE,GAAOC,EAAkB,GAClDF,EAAkBC,GAAOC,EAAkB,GAC5C,IAGwB,OAAvBlI,KAAKF,cACP0G,OAAOC,KAAKzG,KAAKP,oBAAoB8C,SAASmE,IAC5C,GAAgD,eAA5C1G,KAAKP,mBAAmBiH,GAAa,GAAqB,CAC5D,MAAMyB,EAAkBJ,EAAyBrB,GAC3C0B,EAAUJ,EAAkBtB,GAClCpK,EACE,YAAYoK,2DAAqEyB,0CAAwDC,OAE3IpI,KAAKmC,iBAAiBuE,GAAanE,SAAQ,EAAEwB,EAAcb,MACzD,IAAIS,EACsB,WAAtB3D,KAAKD,aAGL4D,EAFW,IAATT,EAEU,EAGA,EAEiB,cAAtBlD,KAAKD,eAGZ4D,EAFW,IAATT,EAEU,EAGA,GAIhB,MAAM0D,EAAkB5G,KAAK8D,IAAIC,GAAcJ,GAAa,EAC5DrH,EACE,qDAAqDsK,EAAkB,cACrE7C,EAAe,iBACDJ,EAAY,MAE9B5G,EAAe6J,KAAqBuB,EAAkBC,EACtDtL,EAAe8J,GAAiBA,IAAoBuB,CAAe,GAEtE,KAE6B,OAAvBnI,KAAKF,eACd0G,OAAOC,KAAKzG,KAAKP,oBAAoB8C,SAASmE,IAC5C,GAAgD,eAA5C1G,KAAKP,mBAAmBiH,GAAa,GAAqB,CAC5D,MAAMyB,EAAkBJ,EAAyBrB,GAC3C0B,EAAUJ,EAAkBtB,GAClCpK,EACE,YAAYoK,2DAAqEyB,0CAAwDC,OAE3IpI,KAAKmC,iBAAiBuE,GAAanE,SAAQ,EAAEwB,EAAcb,MACzD,GAA0B,WAAtBlD,KAAKD,aAA2B,CAClC,IAAIsI,EAAaC,EAAaC,EAAgBC,EAAeC,EAChD,IAATvF,GAEFmF,EAAcpD,EAAY,GAC1BqD,EAAc,EACdC,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATvF,GAETmF,EAAc,EACdC,EAAcrD,EAAY,GAC1BsD,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATvF,GAETmF,EAAcpD,EAAY,GAC1BqD,EAAc,EACdC,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATvF,IAETmF,EAAc,EACdC,EAAcrD,EAAY,GAC1BsD,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GAGlB,IAAIvB,EAA+B7B,EAAepF,kBAAkBoI,EAAaC,GAC7ElI,EAAgB8G,EAA6B9G,cAC7CC,EAAwB6G,EAA6B7G,sBACrDC,EAAwB4G,EAA6B5G,sBAErDsF,EAAY,EACZO,EAAY,EACZD,EAAY,EACZE,EAAY,EAChB,MAAMZ,EAAWxF,KAAK8D,IAAIC,GAAc7H,OACxC,IAAK,IAAIyH,EAAY,EAAGA,EAAY6B,EAAU7B,IAAa,CACzD,MAAMiD,EAAkB5G,KAAK8D,IAAIC,GAAcJ,GAAa,EAG/C,IAATT,GAAuB,IAATA,GAChB0C,GAAatG,EAAkBsH,GAAmBvG,EAAsBsD,GACxEwC,GAAahC,EAAkByC,GAAmBvG,EAAsBsD,IAGxD,IAATT,GAAuB,IAATA,IACrBgD,GAAa5G,EAAkBsH,GAAmBtG,EAAsBqD,GACxEyC,GAAajC,EAAkByC,GAAmBtG,EAAsBqD,GAE3E,CAGD,IAAI+E,EAEFA,EADW,IAATxF,GAAuB,IAATA,EACM/G,KAAKC,KAAKwJ,GAAa,EAAIO,GAAa,GAExChK,KAAKC,KAAK8J,GAAa,EAAIE,GAAa,GAGhE,IACE,IAAIP,EAAiB0C,EACrB1C,EAAiB2C,EACjB3C,GAAkB4C,EAClB,CACA,IAAI7B,EAAkB5G,KAAK8D,IAAIC,GAAc8B,GAAkB,EAC/DvJ,EACE,qDAAqDsK,EAAkB,cACrE7C,EAAe,iBACD8B,EAAiB,MAInC9I,EAAe6J,KACZ1B,EAAa,GACdwD,EACAtI,EAAcyF,GACdsC,EACAC,EAEF,IACE,IAAId,EAAkBiB,EACtBjB,EAAkBkB,EAClBlB,GAAmBmB,EACnB,CACA,IAAIE,EAAmB3I,KAAK8D,IAAIC,GAAcuD,GAAmB,EACjExK,EAAe8J,GAAiB+B,KAC7BzD,EAAa,GACdwD,EACAtI,EAAcyF,GACdzF,EAAckH,GACda,CACH,CACF,CACf,MAAmB,GAA0B,cAAtBnI,KAAKD,aACd,IAAK,IAAI6I,EAAkB,EAAGA,EAAkB,EAAGA,IAAmB,CACpE,IAAIP,EAAaC,EAAaC,EAAgBC,EAAeC,EAChD,IAATvF,GAEFmF,EAAcpD,EAAY2D,GAC1BN,EAAc,EACdC,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATvF,GAETmF,EAAc,EACdC,EAAcrD,EAAY2D,GAC1BL,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATvF,GAETmF,EAAcpD,EAAY2D,GAC1BN,EAAc,EACdC,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATvF,IAETmF,EAAc,EACdC,EAAcrD,EAAY2D,GAC1BL,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GAElB,IAAIvB,EAA+B7B,EAAepF,kBAAkBoI,EAAaC,GAC7ElI,EAAgB8G,EAA6B9G,cAC7CC,EAAwB6G,EAA6B7G,sBACrDC,EAAwB4G,EAA6B5G,sBAErDsF,EAAY,EACZO,EAAY,EACZD,EAAY,EACZE,EAAY,EAChB,MAAMZ,EAAWxF,KAAK8D,IAAIC,GAAc7H,OACxC,IAAK,IAAIyH,EAAY,EAAGA,EAAY6B,EAAU7B,IAAa,CACzD,MAAMiD,EAAkB5G,KAAK8D,IAAIC,GAAcJ,GAAa,EAG/C,IAATT,GAAuB,IAATA,GAChB0C,GAAatG,EAAkBsH,GAAmBvG,EAAsBsD,GACxEwC,GAAahC,EAAkByC,GAAmBvG,EAAsBsD,IAGxD,IAATT,GAAuB,IAATA,IACrBgD,GAAa5G,EAAkBsH,GAAmBtG,EAAsBqD,GACxEyC,GAAajC,EAAkByC,GAAmBtG,EAAsBqD,GAE3E,CAGD,IAAI+E,EAEFA,EADW,IAATxF,GAAuB,IAATA,EACM/G,KAAKC,KAAKwJ,GAAa,EAAIO,GAAa,GAExChK,KAAKC,KAAK8J,GAAa,EAAIE,GAAa,GAGhE,IACE,IAAIP,EAAiB0C,EACrB1C,EAAiB2C,EACjB3C,GAAkB4C,EAClB,CACA,IAAI7B,EAAkB5G,KAAK8D,IAAIC,GAAc8B,GAAkB,EAC/DvJ,EACE,qDAAqDsK,EAAkB,cACrE7C,EAAe,iBACD8B,EAAiB,MAInC9I,EAAe6J,KACZ1B,EAAa0D,GACdF,EACAtI,EAAcyF,GACdsC,EACAC,EAEF,IACE,IAAId,EAAkBiB,EACtBjB,EAAkBkB,EAClBlB,GAAmBmB,EACnB,CACA,IAAIE,EAAmB3I,KAAK8D,IAAIC,GAAcuD,GAAmB,EACjExK,EAAe8J,GAAiB+B,KAC7BzD,EAAa0D,GACdF,EACAtI,EAAcyF,GACdzF,EAAckH,GACda,CACH,CACF,CACF,CACF,GAEJ,IAGN,ECtaI,SAASU,EAAiBC,EAAYrJ,GAE3C,OA0EF,SAAcqJ,EAAYrJ,IAuG1B,SAAiBqJ,GAEf,MAAMhJ,cAAEA,EAAaiB,aAAEA,EAAYE,aAAEA,EAAYD,KAAEA,EAAIE,KAAEA,EAAInB,aAAEA,EAAYoB,WAAEA,GAAe2H,EAE5FC,EAAOC,IAAMjI,EACbgI,EAAOE,IAAMhI,EACb8H,EAAOG,QAAU,EACjBH,EAAOI,QAAU,EACjBJ,EAAOK,MAAQpI,EACf+H,EAAOM,MAAQnI,EACf6H,EAAOO,QAAUP,EAAOK,MAAQL,EAAOG,SAAWH,EAAOC,IACzDD,EAAOQ,QAAUR,EAAOM,MAAQN,EAAOI,SAAWJ,EAAOE,GAC3D,EAhHEO,CAAQV,GAmHV,WACEC,EAAOU,GAAKV,EAAOC,IAAMD,EAAOE,IAChCF,EAAOW,IAAM,EAAIX,EAAOC,IAAM,EAC9BD,EAAOY,IAAM,EAAIZ,EAAOE,IAAM,EAC9BF,EAAOa,GAAKb,EAAOW,IAAMX,EAAOY,IAEhC,IAAIE,EAAM,EACV,IAAK,IAAI5N,EAAI,EAAGA,GAAK8M,EAAOC,IAAK/M,IAC/B,IAAK,IAAIuC,EAAI,EAAGA,GAAKuK,EAAOE,IAAKzK,IAAK,CACpCqL,IACA,IAAK,IAAIC,EAAI,EAAGA,GAAK,EAAGA,IAAK,CAC3B,IAAIC,EAAI,EAAID,EAAI,EAChBf,EAAOjF,IAAI+F,EAAM,GAAGE,EAAI,GAAKhB,EAAOY,KAAO,EAAI1N,EAAI6N,EAAI,GAAK,EAAItL,EAAI,EACpEuK,EAAOjF,IAAI+F,EAAM,GAAGE,GAAKhB,EAAOjF,IAAI+F,EAAM,GAAGE,EAAI,GAAK,EACtDhB,EAAOjF,IAAI+F,EAAM,GAAGE,EAAI,GAAKhB,EAAOjF,IAAI+F,EAAM,GAAGE,EAAI,GAAK,CAC3D,CACF,CAEL,CApIEC,GAuIF,WACEjB,EAAOkB,IAAI,GAAKlB,EAAOG,QACvBH,EAAOmB,IAAI,GAAKnB,EAAOI,QAEvB,IAAK,IAAIlN,EAAI,EAAGA,GAAK8M,EAAOW,IAAKzN,IAAK,CACpC,IAAIuI,GAASvI,EAAI,GAAK8M,EAAOY,IAC7BZ,EAAOkB,IAAIzF,GAASuE,EAAOkB,IAAI,IAAOhO,EAAI,GAAK8M,EAAOO,OAAU,EAChEP,EAAOmB,IAAI1F,GAASuE,EAAOmB,IAAI,GAE/B,IAAK,IAAI1L,EAAI,EAAGA,GAAKuK,EAAOY,IAAKnL,IAC/BuK,EAAOkB,IAAIzF,EAAQhG,EAAI,GAAKuK,EAAOkB,IAAIzF,GACvCuE,EAAOmB,IAAI1F,EAAQhG,EAAI,GAAKuK,EAAOmB,IAAI1F,IAAWhG,EAAI,GAAKuK,EAAOQ,OAAU,CAE/E,CACH,CApJEY,GAIA,IAAK,IAAIlO,EAAI,EAAGA,EAAI8M,EAAOa,GAAI3N,IAC7B8M,EAAOqB,KAAKnO,GAAK,EACjB8M,EAAOsB,GAAGpO,GAAK,EAIjBuK,OAAOC,KAAKhH,GAAoB8C,SAASmE,IAIvC,GAAqB,iBAHHjH,EAAmBiH,GAGvB,GAAuB,CACnC,MAAMmB,EAAYpI,EAAmBiH,GAAa,GAGlD,OAAQA,GACN,IAAK,IACH,IAAK,IAAI4D,EAAM,EAAGA,EAAMvB,EAAOW,IAAKY,IAAO,CACzC,MAAM3G,EAAY2G,EAAMvB,EAAOY,IAC/BZ,EAAOqB,KAAKzG,GAAa,EACzBoF,EAAOsB,GAAG1G,GAAakE,CACxB,CACD,MAEF,IAAK,IACH,IAAK,IAAIrJ,EAAI,EAAGA,EAAIuK,EAAOY,IAAKnL,IAC9BuK,EAAOqB,KAAK5L,GAAK,EACjBuK,EAAOsB,GAAG7L,GAAKqJ,EAEjB,MAEF,IAAK,IACH,IAAK,IAAIyC,EAAM,EAAGA,EAAMvB,EAAOW,IAAKY,IAAO,CACzC,MAAM3G,EAAY2G,EAAMvB,EAAOY,KAAOZ,EAAOY,IAAM,GACnDZ,EAAOqB,KAAKzG,GAAa,EACzBoF,EAAOsB,GAAG1G,GAAakE,CACxB,CACD,MAEF,IAAK,IACH,IAAK,IAAIrJ,EAAI,EAAGA,EAAIuK,EAAOY,IAAKnL,IAAK,CACnC,MAAMmF,GAAaoF,EAAOW,IAAM,GAAKX,EAAOY,IAAMnL,EAClDuK,EAAOqB,KAAKzG,GAAa,EACzBoF,EAAOsB,GAAG1G,GAAakE,CACxB,EAGN,KAKH,IAAK,IAAI5L,EAAI,EAAGA,EAAI8M,EAAOU,GAAIxN,IAC7B8M,EAAOwB,KAAKtO,GAAK,EACjB8M,EAAOyB,KAAKvO,GAAK,EAYnB,IAAK,IAAIA,EAAI,EAAGA,EAAI8M,EAAOa,GAAI3N,IAC7B8M,EAAO0B,GAAGxO,GAAK,EAGjByO,EAAKC,IAAM5B,EAAOa,GAClBc,EAAKE,KAAO,EACZF,EAAKG,KAAO,EACZH,EAAKI,IAAM,EAEX,IAAK,IAAI7O,EAAI,EAAGA,EAAI8M,EAAOU,GAAIxN,IAC7ByO,EAAKK,IAAI9O,GAAK,GAsGlB,WACE,IAaI+O,EAbAC,EAAQ5M,MAAM,GAAGQ,KAAK,GACtBqM,EAAQ7M,MAAM,GAAGQ,KAAK,GACtBsM,EAAO9M,MAAM+M,GAAMvM,KAAK,GACxBwM,EAAOhN,MAAM+M,GAAMvM,KAAK,GACxByM,EAAOjN,MAAM+M,GAAMvM,KAAK,GACxB0M,EAAOlN,MAAM+M,GAAMvM,KAAK,GACxB2M,EAAQnN,MAAM+M,GAAMvM,KAAK,GACzB4M,EAAKpN,MAAM+M,GACZvM,OACA6M,KAAI,IAAMrN,MAAM+M,GAAMvM,KAAK,KAC1B8M,EAAMtN,MAAMuN,GAAO/M,KAAK,GACxBgN,EAAMxN,MAAMuN,GAAO/M,KAAK,GACxBiN,EAAQzN,MAAMuN,GAAO/M,KAAK,GAG1BkN,EAAM,EACVrB,EAAKE,OACL,IAAIoB,EAAO,EACPC,EAAO,EACXC,EAAMC,KAAO,EAEb,IAAK,IAAIlQ,EAAI,EAAGA,EAAIyO,EAAKC,IAAK1O,IAC5B0P,EAAI1P,GAAK,EACT4P,EAAI5P,GAAK,EAGX,GAAkB,IAAdyO,EAAKG,KAAY,CAEnB,IAAK,IAAI5O,EAAI,EAAGA,EAAIyO,EAAKC,IAAK1O,IAC5B6P,EAAM7P,GAAK,EAGb,IAAK,IAAIA,EAAI,EAAGA,EAAI8M,EAAOU,GAAIxN,IAAK,CAClC,IAAImQ,EAAMrD,EAAOU,GAAKxN,EAAI,EAC1B,IAAK,IAAIuC,EAAI,EAAGA,EAAIkM,EAAKK,IAAIqB,GAAM5N,IAAK,CACtC,IAAIsL,EAAIf,EAAOjF,IAAIsI,GAAK5N,GACH,IAAjBsN,EAAMhC,EAAI,KACZgC,EAAMhC,EAAI,GAAK,EACff,EAAOjF,IAAIsI,GAAK5N,IAAMuK,EAAOjF,IAAIsI,GAAK5N,GAEzC,CACF,CACF,CAEDkM,EAAKG,KAAO,EACZ,IAAIwB,EAAO,EACPC,EAAO,EAEX,IAAK,IAAIrQ,EAAI,EAAGA,EAAImP,EAAMnP,IACxB,IAAK,IAAIuC,EAAI,EAAGA,EAAI4M,EAAM5M,IACxBiN,EAAGjN,GAAGvC,GAAK,EAIf,OAAa,CACXiQ,EAAMC,OACNI,IAEA,IAAIrO,EAAIgO,EAAMC,KACVK,EAAO9B,EAAKK,IAAI7M,EAAI,GACpBuO,EAAO/B,EAAKK,IAAI7M,EAAI,GAExB,IAAK,IAAIwO,EAAK,EAAGA,EAAKD,EAAMC,IAAM,CAChC,IACIC,EAqBAC,EAtBAC,EAAO9D,EAAOjF,IAAI5F,EAAI,GAAGwO,GAG7B,GAAa,IAATL,EACFA,IACApB,EAAMyB,GAAML,EACZS,EAAIC,KAAKV,EAAO,GAAKQ,MAChB,CACL,IAAKF,EAAK,EAAGA,EAAKN,GACZlQ,KAAKwC,IAAIkO,KAAU1Q,KAAKwC,IAAImO,EAAIC,KAAKJ,IADnBA,KAIpBA,IAAON,GACTA,IACApB,EAAMyB,GAAML,EACZS,EAAIC,KAAKV,EAAO,GAAKQ,IAErB5B,EAAMyB,GAAMC,EAAK,EACjBG,EAAIC,KAAKJ,GAAME,EAElB,CAGD,GAAa,IAATP,EACFA,IACApB,EAAMwB,GAAMJ,EACZnB,EAAKmB,EAAO,GAAKO,MACZ,CACL,IAAKD,EAAK,EAAGA,EAAKN,GACZnQ,KAAKwC,IAAIkO,KAAU1Q,KAAKwC,IAAIwM,EAAKyB,IADfA,KAIpBA,IAAON,GACTA,IACApB,EAAMwB,GAAMJ,EACZnB,EAAKmB,EAAO,GAAKO,IAEjB3B,EAAMwB,GAAME,EAAK,EACjBzB,EAAKyB,GAAMC,EAEd,CACF,CAED,GAAIP,EAAOlB,GAAQiB,EAAOjB,EAExB,YADAzO,EAAS,qCAIX,IAAK,IAAIoN,EAAI,EAAGA,EAAI0C,EAAM1C,IAAK,CAC7B,IAAI4C,EAAK1B,EAAMlB,GACf,IAAK,IAAID,EAAI,EAAGA,EAAI0C,EAAM1C,IAAK,CAE7B2B,EADSP,EAAMpB,GACP,GAAG6C,EAAK,IAAMT,EAAMc,OAAOlD,GAAGC,EACvC,CACF,CAED,IAAIkD,EAAK,EACT,IAAK,IAAIlD,EAAI,EAAGA,EAAIsC,EAAMtC,IACpB+C,EAAIC,KAAKhD,GAAK,IAChBuB,EAAK2B,GAAMlD,EAAI,EACfkD,KAIJ,IAAIC,EAAK,EACLC,EAAK,EACT,IAAK,IAAIrD,EAAI,EAAGA,EAAIwC,EAAMxC,IAAK,CAC7B,IAAIsD,EAAKjC,EAAKrB,GACd,GAAIsD,EAAK,EAAG,CACV/B,EAAK8B,GAAMrD,EAAI,EACfqD,IACA,IAAIE,EAAMlR,KAAKwC,IAAIyO,GACU,IAAzBrE,EAAOqB,KAAKiD,EAAM,KACpB9B,EAAK2B,GAAMpD,EAAI,EACfoD,IACAnE,EAAOqB,KAAKiD,EAAM,GAAK,EACvBtE,EAAO0B,GAAG4C,EAAM,GAAKtE,EAAOsB,GAAGgD,EAAM,GAExC,CACF,CAED,GAAIH,EAAK,EACP,IAAK,IAAII,EAAM,EAAGA,EAAMJ,EAAII,IAAO,CACjC,IAAIxD,EAAIyB,EAAK+B,GAAO,EAChBC,EAAKpR,KAAKwC,IAAIwM,EAAKrB,IACvB,IAAK,IAAIC,EAAI,EAAGA,EAAIsC,EAAMtC,IAAK,CAC7B0B,EAAG3B,GAAGC,GAAK,EACF5N,KAAKwC,IAAImO,EAAIC,KAAKhD,MAChBwD,IAAI9B,EAAG3B,GAAGC,GAAK,EAC3B,CACF,CAGH,GAAIkD,EAAKhB,GAAQC,EAAMC,KAAOpD,EAAOU,GAAI,CACvC,GAAW,IAAPwD,EAEF,YADAtQ,EAAS,oCAIX,IAAI6Q,EAASnC,EAAK,GACdoC,EAASnC,EAAK,GACdoC,EAAQjC,EAAG+B,EAAS,GAAGC,EAAS,GAEpC,GAAItR,KAAKwC,IAAI+O,GAAS,KAAM,CAC1BA,EAAQ,EACR,IAAK,IAAI3D,EAAI,EAAGA,EAAIkD,EAAIlD,IAAK,CAC3B,IAAI4D,EAAQrC,EAAKvB,GACjB,IAAK,IAAID,EAAI,EAAGA,EAAIqD,EAAIrD,IAAK,CAC3B,IAAI8D,EAAQvC,EAAKvB,GACb+D,EAAOpC,EAAGmC,EAAQ,GAAGD,EAAQ,GAC7BxR,KAAKwC,IAAIkP,GAAQ1R,KAAKwC,IAAI+O,KAC5BA,EAAQG,EACRJ,EAASE,EACTH,EAASI,EAEZ,CACF,CACF,CAED,IAAIP,EAAMlR,KAAKwC,IAAIwM,EAAKqC,EAAS,IACjCxC,EAAM7O,KAAKwC,IAAImO,EAAIC,KAAKU,EAAS,IACjC,IAAIK,EAAOT,EAAMrC,EAAMW,EAAI0B,EAAM,GAAKxB,EAAIb,EAAM,GAChDN,EAAKI,IAAOJ,EAAKI,IAAM4C,IAAU,IAAMI,EAAQ3R,KAAKwC,IAAI+O,GAExD,IAAK,IAAIK,EAAQ,EAAGA,EAAQrD,EAAKC,IAAKoD,IAChCA,GAASV,GAAK1B,EAAIoC,KAClBA,GAAS/C,GAAKa,EAAIkC,KASxB,GANI5R,KAAKwC,IAAI+O,GAAS,OACpB/Q,EACE,qDAAqDuP,EAAMC,aAAakB,UAAYrC,YAAc0C,KAIxF,IAAVA,EAAa,OAEjB,IAAK,IAAI3D,EAAI,EAAGA,EAAIsC,EAAMtC,IACxB+C,EAAIkB,GAAGjE,GAAK0B,EAAG+B,EAAS,GAAGzD,GAAK2D,EAGlC,IAAIO,EAAMlF,EAAO0B,GAAG4C,EAAM,GAAKK,EAI/B,GAHA3E,EAAO0B,GAAG4C,EAAM,GAAKY,EACrBzC,EAAMgC,EAAS,GAAKE,EAEhBF,EAAS,EACX,IAAK,IAAI1D,EAAI,EAAGA,EAAI0D,EAAS,EAAG1D,IAAK,CACnC,IAAIoE,EAAM/R,KAAKwC,IAAIwM,EAAKrB,IACpBqE,EAAM1C,EAAG3B,GAAG2D,EAAS,GAEzB,GADAjC,EAAM1B,GAAKqE,EACPV,EAAS,GAAa,IAARU,EAChB,IAAK,IAAIpE,EAAI,EAAGA,EAAI0D,EAAS,EAAG1D,IAC9B0B,EAAG3B,GAAGC,IAAMoE,EAAMrB,EAAIkB,GAAGjE,GAG7B,GAAI0D,EAASpB,EACX,IAAK,IAAItC,EAAI0D,EAAQ1D,EAAIsC,EAAMtC,IAC7B0B,EAAG3B,GAAGC,EAAI,GAAK0B,EAAG3B,GAAGC,GAAKoE,EAAMrB,EAAIkB,GAAGjE,GAG3ChB,EAAO0B,GAAGyD,EAAM,IAAMC,EAAMF,CAC7B,CAGH,GAAIT,EAASlB,EACX,IAAK,IAAIxC,EAAI0D,EAAQ1D,EAAIwC,EAAMxC,IAAK,CAClC,IAAIoE,EAAM/R,KAAKwC,IAAIwM,EAAKrB,IACpBqE,EAAM1C,EAAG3B,GAAG2D,EAAS,GAEzB,GADAjC,EAAM1B,GAAKqE,EACPV,EAAS,EACX,IAAK,IAAI1D,EAAI,EAAGA,EAAI0D,EAAS,EAAG1D,IAC9B0B,EAAG3B,EAAI,GAAGC,GAAK0B,EAAG3B,GAAGC,GAAKoE,EAAMrB,EAAIkB,GAAGjE,GAG3C,GAAI0D,EAASpB,EACX,IAAK,IAAItC,EAAI0D,EAAQ1D,EAAIsC,EAAMtC,IAC7B0B,EAAG3B,EAAI,GAAGC,EAAI,GAAK0B,EAAG3B,GAAGC,GAAKoE,EAAMrB,EAAIkB,GAAGjE,GAG/ChB,EAAO0B,GAAGyD,EAAM,IAAMC,EAAMF,CAC7B,CAGH,IAAK,IAAIhS,EAAI,EAAGA,EAAIqQ,EAAMrQ,IACxB6Q,EAAIsB,MAAMpC,EAAO/P,EAAI,GAAKuP,EAAMvP,GAElC+P,GAAQM,EAER,IAAK,IAAIrQ,EAAI,EAAGA,EAAIqQ,EAAMrQ,IACxB6Q,EAAIsB,MAAMpC,EAAO/P,EAAI,GAAKkP,EAAKlP,GAEjC+P,GAAQM,EAERQ,EAAIsB,MAAMpC,EAAO,GAAKwB,EACtBxB,IAEA,IAAK,IAAI/P,EAAI,EAAGA,EAAIoQ,EAAMpQ,IACxB6Q,EAAIuB,IAAItC,EAAM,EAAI9P,GAAK6Q,EAAIkB,GAAG/R,GAEhC8P,GAAOM,EAEP,IAAK,IAAIpQ,EAAI,EAAGA,EAAIoQ,EAAMpQ,IACxB6Q,EAAIuB,IAAItC,EAAM,EAAI9P,GAAK6Q,EAAIC,KAAK9Q,GAElC8P,GAAOM,EAEPS,EAAIuB,IAAItC,EAAM,GAAKsB,EACnBP,EAAIuB,IAAItC,GAAOM,EACfS,EAAIuB,IAAItC,EAAM,GAAK0B,EACnBX,EAAIuB,IAAItC,EAAM,GAAK2B,EACnB3B,GAAO,EAEP,IAAK,IAAIjC,EAAI,EAAGA,EAAIwC,EAAMxC,IACxB2B,EAAG3B,GAAGuC,EAAO,GAAK,EAGpB,IAAK,IAAItC,EAAI,EAAGA,EAAIsC,EAAMtC,IACxB0B,EAAGa,EAAO,GAAGvC,GAAK,EAIpB,GADAsC,IACIoB,EAASpB,EAAO,EAClB,IAAK,IAAItC,EAAI0D,EAAS,EAAG1D,EAAIsC,EAAMtC,IACjC+C,EAAIC,KAAKhD,GAAK+C,EAAIC,KAAKhD,EAAI,GAK/B,GADAuC,IACIkB,EAASlB,EAAO,EAClB,IAAK,IAAIxC,EAAI0D,EAAS,EAAG1D,EAAIwC,EAAMxC,IACjCqB,EAAKrB,GAAKqB,EAAKrB,EAAI,GAIvB,GAAIwC,EAAO,GAAKJ,EAAMC,KAAOpD,EAAOU,GAAI,SAiBxC,GAfAuB,EAAM7O,KAAKwC,IAAImO,EAAIC,KAAK,IACxBS,EAAS,EACTE,EAAQjC,EAAG,GAAG,GACd4B,EAAMlR,KAAKwC,IAAIwM,EAAK,IACpBsC,EAAS,EACTK,EAAOT,EAAMrC,EAAMW,EAAI0B,EAAM,GAAKxB,EAAIb,EAAM,GAC5CN,EAAKI,IAAOJ,EAAKI,IAAM4C,IAAU,IAAMI,EAAQ3R,KAAKwC,IAAI+O,GAExDZ,EAAIkB,GAAG,GAAK,EACR7R,KAAKwC,IAAI+O,GAAS,OACpB/Q,EACE,qDAAqDuP,EAAMC,aAAakB,UAAYrC,YAAc0C,KAIxF,IAAVA,EAAa,OAEjB3E,EAAO0B,GAAG4C,EAAM,GAAKtE,EAAO0B,GAAG4C,EAAM,GAAKK,EAC1CZ,EAAIuB,IAAItC,EAAM,GAAKe,EAAIkB,GAAG,GAC1BjC,IACAe,EAAIuB,IAAItC,EAAM,GAAKe,EAAIC,KAAK,GAC5BhB,IACAe,EAAIuB,IAAItC,EAAM,GAAKsB,EACnBP,EAAIuB,IAAItC,GAAOM,EACfS,EAAIuB,IAAItC,EAAM,GAAK0B,EACnBX,EAAIuB,IAAItC,EAAM,GAAK2B,EACnB3B,GAAO,EAEPe,EAAIsB,MAAMpC,EAAO,GAAKR,EAAM,GAC5BQ,IACAc,EAAIsB,MAAMpC,EAAO,GAAKb,EAAK,GAC3Ba,IACAc,EAAIsB,MAAMpC,EAAO,GAAKwB,EACtBxB,IAEAtB,EAAK4D,KAAOvC,EACM,IAAdrB,EAAKE,MAAYtO,EAAS,0CAA0CyP,KAExEwC,EAAOxC,GACP,KACD,CACF,CACH,CAzbEyC,GAGA,IAAK,IAAIvS,EAAI,EAAGA,EAAI8M,EAAOa,GAAI3N,IAC7B8M,EAAO0F,EAAExS,GAAKyO,EAAKgE,GAAGzS,GAIxB,IAAK,IAAIA,EAAI,EAAGA,EAAI8M,EAAOa,GAAI3N,IAC7BK,EACE,GAAGyM,EAAOkB,IAAIhO,GAAG0D,cAAc,OAAOoJ,EAAOmB,IAAIjO,GAAG0D,cAAc,OAAOoJ,EAAO0F,EAAExS,GAAG0D,cAAc,KAGzG,CA/KEgP,CAAK7F,EAAYrJ,GACV,CACLtC,eAAgB4L,EAAO0F,EAAEG,MAAM,EAAG7F,EAAOa,IACzCiF,iBAAkB,CAChBvP,kBAAmByJ,EAAOkB,IAAI2E,MAAM,EAAG7F,EAAOa,IAC9CzF,kBAAmB4E,EAAOmB,IAAI0E,MAAM,EAAG7F,EAAOa,KAGpD,CAGA,MAAMkF,EAAQ,KACRlD,EAAQ,KACRR,EAAO,IAGPrC,EAAS,CACbC,IAAK,EACLC,IAAK,EACLS,IAAK,EACLC,IAAK,EACLF,GAAI,EACJG,GAAI,EACJV,QAAS,EACTC,QAAS,EACTC,MAAO,EACPC,MAAO,EACPC,OAAQ,EACRC,OAAQ,EACRzF,IAAKzF,MAAMyQ,GACRjQ,OACA6M,KAAI,IAAMrN,MAAM,GAAGQ,KAAK,KAC3BoL,IAAK5L,MAAMuN,GAAO/M,KAAK,GACvBqL,IAAK7L,MAAMuN,GAAO/M,KAAK,GACvBuL,KAAM/L,MAAMuN,GAAO/M,KAAK,GACxBwL,GAAIhM,MAAMuN,GAAO/M,KAAK,GACtB4L,GAAIpM,MAAMuN,GAAO/M,KAAK,GACtB4P,EAAGpQ,MAAMuN,GAAO/M,KAAK,GACrB0L,KAAMlM,MAAMyQ,GAAOjQ,KAAK,GACxB2L,KAAMnM,MAAMyQ,GAAOjQ,KAAK,IAGpBkQ,EAAQ,CACZC,EAAG,CAAC,gBAAkB,cAAgB,iBACtCC,GAAI,CAAC,YAAc,GAAK,cAGpBvE,EAAO,CACXE,KAAM,EACND,IAAK,EACLE,KAAM,EACNE,IAAK1M,MAAMyQ,GAAOjQ,KAAK,GACvBiM,IAAK,EACL4D,GAAIrQ,MAAM+M,EAAOA,GAAMvM,KAAK,GAC5ByP,KAAM,GAGFpC,EAAQ,CACZc,OAAQ3O,MAAM,GACXQ,OACA6M,KAAI,IAAMrN,MAAM,GAAGQ,KAAK,KAC3BsN,KAAM,GAGFW,EAAM,CACVuB,IAAKhQ,MAAM,KAASQ,KAAK,GACzBkO,KAAM1O,MAAM+M,GAAMvM,KAAK,GACvBmP,GAAI3P,MAAM+M,GAAMvM,KAAK,GACrBuP,MAAO/P,MAAM,KAASQ,KAAK,IAIvBqQ,EAAoB,IAAItP,EAAe,CAAEE,cAAe,KAAMC,aAAc,cA+JlF,SAASwM,IACP,MAAMxI,EAAemI,EAAMC,KAAO,GAE5Ba,OAAEA,EAAMmC,UAAEA,EAASC,IAAEA,GCvEtB,UAAwCrL,aAC7CA,EAAYD,IACZA,EAAG6B,aACHA,EAAYM,aACZA,EAAYZ,eACZA,EAAcJ,YACdA,EAAWC,aACXA,EAAYmK,SACZA,GAAW,EAAKC,SAChBA,GAAW,EAAKC,cAChBA,EAAgB,CAAEC,QAAQ,EAAOC,MAAO,EAAGrH,QAAS,KAEpD,MACM4E,EAAS3O,MADE,GAEdQ,OACA6M,KAAI,IAAMrN,MAHI,GAGYQ,KAAK,KAC5BsQ,EAAY9Q,MAJD,GAIiBQ,KAAK,GAGjCuQ,EAAM/Q,MAPK,GAQjB,IAAK,IAAIpC,EAAI,EAAGA,EARC,EAQaA,IAAKmT,EAAInT,GAAKE,KAAKwC,IAAImF,EAAIC,GAAc9H,IAGvE,IAAK,IAAIuC,EAAI,EAAGA,EAAIyG,EAAY/I,OAAQsC,IACtC,IAAK,IAAIsL,EAAI,EAAGA,EAAI7E,EAAY/I,OAAQ4N,IAAK,CAC3C,MAAM1J,cAAEA,EAAaC,sBAAEA,EAAqBC,sBAAEA,GAC5C+E,EAAepF,kBAAkBgF,EAAYzG,GAAIyG,EAAY6E,IAEzDvE,EAAmB6J,EAAI1D,KAAKgE,GAAMA,EAAI,KAEtC5J,YAAEA,EAAWC,oBAAEA,EAAmBM,oBAAEA,GAAwBL,EAA8B,CAC9F5F,gBACAC,wBACAC,wBACAhB,kBAAmBqG,EACnBxB,kBAAmB8B,EACnBV,mBACAC,SAzBW,IA4Bb,IAAK,IAAImK,EAAI,EAAGA,EA5BH,EA4BiBA,IAC5B,IAAK,IAAIC,EAAI,EAAGA,EA7BL,EA6BmBA,IAC5B5C,EAAO2C,GAAGC,IACR1K,EAAa1G,GACb0G,EAAa4E,GACbhE,GACCC,EAAoB4J,GAAK5J,EAAoB6J,GAC5CvJ,EAAoBsJ,GAAKtJ,EAAoBuJ,GAGtD,CAKH,GAAIP,GAAYE,EAAcC,OAAQ,CACpC,MAAMK,EAAIN,EAAcE,MAClBK,EAAOP,EAAcnH,QAE3B,IAAK,IAAI6G,EAAK,EAAGA,EAAKhK,EAAY/I,OAAQ+S,IAAM,CAC9C,MAAM/O,EAAM+E,EAAYgK,IAClB7O,cAAEA,EAAaC,sBAAEA,GAA0BgF,EAAepF,kBAAkBC,EAAK,GAGvF,IAAI6P,EAAU,EAAGC,EAAU,EAC3B,MAAMC,EAAoB,CAAC,EAAG,EAAG,GACjC,IAAK,IAAI/R,EAAI,EAAGA,EAAI,EAAGA,IAAK,CAC1B,MAAMwR,EAAI5L,EAAIC,GAAc7F,GAAK,EACjC6R,GAAWpK,EAAa+J,GAAKrP,EAAsBnC,GACnD8R,GAAW/J,EAAayJ,GAAKrP,EAAsBnC,EACpD,CACD,MAAMgS,EAAU/T,KAAKC,KAAK2T,EAAUA,EAAUC,EAAUA,GAGxD,IAAK,MAAML,KAAKM,EAAmB,CACjC,IAAK,MAAML,KAAKK,EACdjD,EAAO2C,GAAGC,IAAM1K,EAAa+J,GAAMiB,EAAUL,EAAIzP,EAAcuP,GAAKvP,EAAcwP,GAEpFT,EAAUQ,IAAMzK,EAAa+J,GAAMiB,EAAUL,EAAIC,EAAO1P,EAAcuP,EACvE,CACF,CACF,MAAUN,GAAaE,EAAcC,OAOtC,MAAO,CAAExC,SAAQmC,YAAWC,MAC9B,CDlBqCe,CAA+B,CAChEpM,eACAD,IAAKiF,EAAOjF,IACZ6B,aAAcoD,EAAOkB,IACrBhE,aAAc8C,EAAOmB,IACrB7E,eAAgB6J,EAChBjK,YAAa8J,EAAME,GACnB/J,aAAc6J,EAAMC,EACpBK,SAAwC,IAA9BtG,EAAOwB,KAAKxG,GACtBuL,SAAwC,IAA9BvG,EAAOyB,KAAKzG,KAIxB,IAAK,IAAI9H,EAAI,EAAGA,EAAI,EAAGA,IACrB,IAAK,IAAIuC,EAAI,EAAGA,EAAI,EAAGA,IACrB0N,EAAMc,OAAO/Q,GAAGuC,GAAKwO,EAAO/Q,GAAGuC,GAKnC,IAAK,IAAImR,EAAI,EAAGA,EAAI,EAAGA,IAAK,CAC1B,MAAMD,EAAIN,EAAIO,GAAK,EACnB5G,EAAO0B,GAAGiF,IAAMP,EAAUQ,EAC3B,CACH,CA4VA,SAASpB,EAAOxC,GACd,IAAK,IAAI9P,EAAI,EAAGA,EAAIyO,EAAKC,IAAK1O,IAC5ByO,EAAKgE,GAAGzS,GAAK8M,EAAOsB,GAAGpO,GAGzB,IAAK,IAAImU,EAAK,EAAGA,GAAM1F,EAAKC,IAAKyF,IAAM,CACrCrE,GAAO,EACP,IAAIsB,EAAMP,EAAIuB,IAAItC,EAAM,GACpBM,EAAOS,EAAIuB,IAAItC,GACf0B,EAASX,EAAIuB,IAAItC,EAAM,GAG3B,GAFYe,EAAIuB,IAAItC,EAAM,GAEf,IAAPqE,EACFrE,IACAe,EAAIC,KAAK,GAAKD,EAAIuB,IAAItC,EAAM,GAC5BA,IACAe,EAAIkB,GAAG,GAAKlB,EAAIuB,IAAItC,EAAM,OACrB,CACLA,GAAOM,EACP,IAAK,IAAIgE,EAAM,EAAGA,EAAMhE,EAAMgE,IAC5BvD,EAAIC,KAAKsD,GAAOvD,EAAIuB,IAAItC,EAAM,EAAIsE,GAEpCtE,GAAOM,EACP,IAAK,IAAIgE,EAAM,EAAGA,EAAMhE,EAAMgE,IAC5BvD,EAAIkB,GAAGqC,GAAOvD,EAAIuB,IAAItC,EAAM,EAAIsE,EAEnC,CAED,IAAIrF,EAAM7O,KAAKwC,IAAImO,EAAIC,KAAKU,EAAS,IACrC,GAAI1E,EAAOqB,KAAKY,EAAM,GAAK,EAAG,SAE9B,IAAIsF,EAAO,EACXxD,EAAIkB,GAAGP,EAAS,GAAK,EACrB,IAAK,IAAI1D,EAAI,EAAGA,EAAIsC,EAAMtC,IACxBuG,GAAQxD,EAAIkB,GAAGjE,GAAKW,EAAKgE,GAAGvS,KAAKwC,IAAImO,EAAIC,KAAKhD,IAAM,GAGtDW,EAAKgE,GAAG1D,EAAM,GAAKsF,EAAOvH,EAAO0B,GAAG4C,EAAM,GAE1CtE,EAAOqB,KAAKY,EAAM,GAAK,CACxB,CAEiB,IAAdN,EAAKE,MAAYtO,EAAS,uCAAuCyP,IACvE;;;;;;AErpBA,MAAMwE,EAAcC,OAAO,iBACrBC,EAAiBD,OAAO,oBACxBE,EAAeF,OAAO,wBACtBG,EAAYH,OAAO,qBACnBI,EAAcJ,OAAO,kBACrBK,EAAYC,GAAwB,iBAARA,GAA4B,OAARA,GAAgC,mBAARA,EAgDxEC,EAAmB,IAAIC,IAAI,CAC7B,CAAC,QA7CwB,CACzBC,UAAYH,GAAQD,EAASC,IAAQA,EAAIP,GACzC,SAAAW,CAAUC,GACN,MAAMC,MAAEA,EAAKC,MAAEA,GAAU,IAAIC,eAE7B,OADAC,EAAOJ,EAAKC,GACL,CAACC,EAAO,CAACA,GACnB,EACDG,YAAYC,IACRA,EAAKC,QACEC,EAAKF,MAqChB,CAAC,QA/BwB,CACzBR,UAAYtK,GAAUkK,EAASlK,IAAUiK,KAAejK,EACxD,SAAAuK,EAAUvK,MAAEA,IACR,IAAIiL,EAcJ,OAZIA,EADAjL,aAAiBkL,MACJ,CACTC,SAAS,EACTnL,MAAO,CACHpK,QAASoK,EAAMpK,QACfuG,KAAM6D,EAAM7D,KACZiP,MAAOpL,EAAMoL,QAKR,CAAED,SAAS,EAAOnL,SAE5B,CAACiL,EAAY,GACvB,EACD,WAAAJ,CAAYI,GACR,GAAIA,EAAWE,QACX,MAAMtL,OAAOwL,OAAO,IAAIH,MAAMD,EAAWjL,MAAMpK,SAAUqV,EAAWjL,OAExE,MAAMiL,EAAWjL,KACpB,MAoBL,SAAS4K,EAAOJ,EAAKc,EAAKC,WAAYC,EAAiB,CAAC,MACpDF,EAAGG,iBAAiB,WAAW,SAASC,EAASC,GAC7C,IAAKA,IAAOA,EAAGC,KACX,OAEJ,IAhBR,SAAyBJ,EAAgBK,GACrC,IAAK,MAAMC,KAAiBN,EAAgB,CACxC,GAAIK,IAAWC,GAAmC,MAAlBA,EAC5B,OAAO,EAEX,GAAIA,aAAyBC,QAAUD,EAAcE,KAAKH,GACtD,OAAO,CAEd,CACD,OAAO,CACX,CAMaI,CAAgBT,EAAgBG,EAAGE,QAEpC,YADAhW,QAAQqW,KAAK,mBAAmBP,EAAGE,6BAGvC,MAAMM,GAAEA,EAAEC,KAAEA,EAAIC,KAAEA,GAASxM,OAAOwL,OAAO,CAAEgB,KAAM,IAAMV,EAAGC,MACpDU,GAAgBX,EAAGC,KAAKU,cAAgB,IAAIvH,IAAIwH,GACtD,IAAIC,EACJ,IACI,MAAMC,EAASJ,EAAKpE,MAAM,GAAI,GAAGyE,QAAO,CAAClC,EAAK3O,IAAS2O,EAAI3O,IAAO2O,GAC5DmC,EAAWN,EAAKK,QAAO,CAAClC,EAAK3O,IAAS2O,EAAI3O,IAAO2O,GACvD,OAAQ4B,GACJ,IAAK,MAEGI,EAAcG,EAElB,MACJ,IAAK,MAEGF,EAAOJ,EAAKpE,OAAO,GAAG,IAAMsE,EAAcZ,EAAGC,KAAK5L,OAClDwM,GAAc,EAElB,MACJ,IAAK,QAEGA,EAAcG,EAASC,MAAMH,EAAQH,GAEzC,MACJ,IAAK,YAGGE,EA+LxB,SAAehC,GACX,OAAO3K,OAAOwL,OAAOb,EAAK,CAAEZ,CAACA,IAAc,GAC/C,CAjMsCiD,CADA,IAAIF,KAAYL,IAGlC,MACJ,IAAK,WACD,CACI,MAAM7B,MAAEA,EAAKC,MAAEA,GAAU,IAAIC,eAC7BC,EAAOJ,EAAKE,GACZ8B,EAoLxB,SAAkBhC,EAAKsC,GAEnB,OADAC,EAAcC,IAAIxC,EAAKsC,GAChBtC,CACX,CAvLsCyC,CAASxC,EAAO,CAACA,GAClC,CACD,MACJ,IAAK,UAEG+B,OAAc/Q,EAElB,MACJ,QACI,OAEX,CACD,MAAOuE,GACHwM,EAAc,CAAExM,QAAOiK,CAACA,GAAc,EACzC,CACDiD,QAAQC,QAAQX,GACXY,OAAOpN,IACD,CAAEA,QAAOiK,CAACA,GAAc,MAE9BoD,MAAMb,IACP,MAAOc,EAAWC,GAAiBC,EAAYhB,GAC/ClB,EAAGmC,YAAY5N,OAAOwL,OAAOxL,OAAOwL,OAAO,GAAIiC,GAAY,CAAEnB,OAAOoB,GACvD,YAATnB,IAEAd,EAAGoC,oBAAoB,UAAWhC,GAClCiC,EAAcrC,GACVtB,KAAaQ,GAAiC,mBAAnBA,EAAIR,IAC/BQ,EAAIR,KAEX,IAEAoD,OAAOQ,IAER,MAAON,EAAWC,GAAiBC,EAAY,CAC3CxN,MAAO,IAAI6N,UAAU,+BACrB5D,CAACA,GAAc,IAEnBqB,EAAGmC,YAAY5N,OAAOwL,OAAOxL,OAAOwL,OAAO,GAAIiC,GAAY,CAAEnB,OAAOoB,EAAc,GAE9F,IACQjC,EAAGP,OACHO,EAAGP,OAEX,CAIA,SAAS4C,EAAcG,IAHvB,SAAuBA,GACnB,MAAqC,gBAA9BA,EAAS5U,YAAYiD,IAChC,EAEQ4R,CAAcD,IACdA,EAASE,OACjB,CACA,SAAShD,EAAKM,EAAI2C,GACd,MAAMC,EAAmB,IAAI7D,IAiB7B,OAhBAiB,EAAGG,iBAAiB,WAAW,SAAuBE,GAClD,MAAMC,KAAEA,GAASD,EACjB,IAAKC,IAASA,EAAKO,GACf,OAEJ,MAAMgC,EAAWD,EAAiBE,IAAIxC,EAAKO,IAC3C,GAAKgC,EAGL,IACIA,EAASvC,EACZ,CACO,QACJsC,EAAiBG,OAAOzC,EAAKO,GAChC,CACT,IACWmC,EAAYhD,EAAI4C,EAAkB,GAAID,EACjD,CACA,SAASM,EAAqBC,GAC1B,GAAIA,EACA,MAAM,IAAItD,MAAM,6CAExB,CACA,SAASuD,EAAgBnD,GACrB,OAAOoD,EAAuBpD,EAAI,IAAIjB,IAAO,CACzC+B,KAAM,YACPiB,MAAK,KACJM,EAAcrC,EAAG,GAEzB,CACA,MAAMqD,EAAe,IAAIC,QACnBC,EAAkB,yBAA0BtD,YAC9C,IAAIuD,sBAAsBxD,IACtB,MAAMyD,GAAYJ,EAAaP,IAAI9C,IAAO,GAAK,EAC/CqD,EAAa3B,IAAI1B,EAAIyD,GACJ,IAAbA,GACAN,EAAgBnD,EACnB,IAcT,SAASgD,EAAYhD,EAAI4C,EAAkB7B,EAAO,GAAI4B,EAAS,cAC3D,IAAIe,GAAkB,EACtB,MAAMnC,EAAQ,IAAIoC,MAAMhB,EAAQ,CAC5B,GAAAG,CAAIc,EAASrT,GAET,GADA0S,EAAqBS,GACjBnT,IAASkO,EACT,MAAO,MAXvB,SAAyB8C,GACjBgC,GACAA,EAAgBM,WAAWtC,EAEnC,CAQoBuC,CAAgBvC,GAChB4B,EAAgBnD,GAChB4C,EAAiBmB,QACjBL,GAAkB,CAAI,EAG9B,GAAa,SAATnT,EAAiB,CACjB,GAAoB,IAAhBwQ,EAAK9W,OACL,MAAO,CAAE8X,KAAM,IAAMR,GAEzB,MAAMyC,EAAIZ,EAAuBpD,EAAI4C,EAAkB,CACnD9B,KAAM,MACNC,KAAMA,EAAKtH,KAAKwK,GAAMA,EAAEC,eACzBnC,KAAKd,GACR,OAAO+C,EAAEjC,KAAKoC,KAAKH,EACtB,CACD,OAAOhB,EAAYhD,EAAI4C,EAAkB,IAAI7B,EAAMxQ,GACtD,EACD,GAAAmR,CAAIkC,EAASrT,EAAM8Q,GACf4B,EAAqBS,GAGrB,MAAOhP,EAAOuN,GAAiBC,EAAYb,GAC3C,OAAO+B,EAAuBpD,EAAI4C,EAAkB,CAChD9B,KAAM,MACNC,KAAM,IAAIA,EAAMxQ,GAAMkJ,KAAKwK,GAAMA,EAAEC,aACnCxP,SACDuN,GAAeF,KAAKd,EAC1B,EACD,KAAAK,CAAMsC,EAASQ,EAAUC,GACrBpB,EAAqBS,GACrB,MAAMY,EAAOvD,EAAKA,EAAK9W,OAAS,GAChC,GAAIqa,IAAS9F,EACT,OAAO4E,EAAuBpD,EAAI4C,EAAkB,CAChD9B,KAAM,aACPiB,KAAKd,GAGZ,GAAa,SAATqD,EACA,OAAOtB,EAAYhD,EAAI4C,EAAkB7B,EAAKpE,MAAM,GAAI,IAE5D,MAAOqE,EAAciB,GAAiBsC,EAAiBF,GACvD,OAAOjB,EAAuBpD,EAAI4C,EAAkB,CAChD9B,KAAM,QACNC,KAAMA,EAAKtH,KAAKwK,GAAMA,EAAEC,aACxBlD,gBACDiB,GAAeF,KAAKd,EAC1B,EACD,SAAAuD,CAAUZ,EAASS,GACfpB,EAAqBS,GACrB,MAAO1C,EAAciB,GAAiBsC,EAAiBF,GACvD,OAAOjB,EAAuBpD,EAAI4C,EAAkB,CAChD9B,KAAM,YACNC,KAAMA,EAAKtH,KAAKwK,GAAMA,EAAEC,aACxBlD,gBACDiB,GAAeF,KAAKd,EAC1B,IAGL,OA9EJ,SAAuBM,EAAOvB,GAC1B,MAAMyD,GAAYJ,EAAaP,IAAI9C,IAAO,GAAK,EAC/CqD,EAAa3B,IAAI1B,EAAIyD,GACjBF,GACAA,EAAgBkB,SAASlD,EAAOvB,EAAIuB,EAE5C,CAuEImD,CAAcnD,EAAOvB,GACduB,CACX,CAIA,SAASgD,EAAiBvD,GACtB,MAAM2D,EAAY3D,EAAavH,IAAIyI,GACnC,MAAO,CAACyC,EAAUlL,KAAKmL,GAAMA,EAAE,MALnBC,EAK+BF,EAAUlL,KAAKmL,GAAMA,EAAE,KAJ3DxY,MAAM0Y,UAAUC,OAAOzD,MAAM,GAAIuD,KAD5C,IAAgBA,CAMhB,CACA,MAAMpD,EAAgB,IAAI6B,QAe1B,SAASpB,EAAYxN,GACjB,IAAK,MAAO7D,EAAMmU,KAAYlG,EAC1B,GAAIkG,EAAQhG,UAAUtK,GAAQ,CAC1B,MAAOuQ,EAAiBhD,GAAiB+C,EAAQ/F,UAAUvK,GAC3D,MAAO,CACH,CACIoM,KAAM,UACNjQ,OACA6D,MAAOuQ,GAEXhD,EAEP,CAEL,MAAO,CACH,CACInB,KAAM,MACNpM,SAEJ+M,EAAcqB,IAAIpO,IAAU,GAEpC,CACA,SAASuM,EAAcvM,GACnB,OAAQA,EAAMoM,MACV,IAAK,UACD,OAAOhC,EAAiBgE,IAAIpO,EAAM7D,MAAM0O,YAAY7K,EAAMA,OAC9D,IAAK,MACD,OAAOA,EAAMA,MAEzB,CACA,SAAS0O,EAAuBpD,EAAI4C,EAAkBsC,EAAK1D,GACvD,OAAO,IAAII,SAASC,IAChB,MAAMhB,EASH,IAAIzU,MAAM,GACZQ,KAAK,GACL6M,KAAI,IAAMvP,KAAKib,MAAMjb,KAAKkb,SAAW7X,OAAO8X,kBAAkBnB,SAAS,MACvE7S,KAAK,KAXNuR,EAAiBlB,IAAIb,EAAIgB,GACrB7B,EAAGP,OACHO,EAAGP,QAEPO,EAAGmC,YAAY5N,OAAOwL,OAAO,CAAEc,MAAMqE,GAAM1D,EAAU,GAE7D,wBClUO,MACL,WAAA5T,GACEG,KAAKuX,aAAe,KACpBvX,KAAK8I,WAAa,GAClB9I,KAAKP,mBAAqB,GAC1BO,KAAKnD,aAAe,UACpBH,EAAS,kCACV,CAED,eAAA8a,CAAgBD,GACdvX,KAAKuX,aAAeA,EACpBjb,EAAS,yBAAyBib,IACnC,CAED,aAAAE,CAAc3O,GACZ9I,KAAK8I,WAAaA,EAClBxM,EAAS,oCAAoCwM,EAAWhJ,gBACzD,CAED,oBAAA4X,CAAqBhR,EAAaiR,GAChC3X,KAAKP,mBAAmBiH,GAAeiR,EACvCrb,EAAS,0CAA0CoK,YAAsBiR,EAAU,KACpF,CAED,eAAAC,CAAgB/a,GACdmD,KAAKnD,aAAeA,EACpBP,EAAS,yBAAyBO,IACnC,CAED,KAAAgb,GACE,IAAK7X,KAAKuX,eAAiBvX,KAAK8I,aAAe9I,KAAKP,mBAAoB,CACtE,MAAM8U,EAAQ,kFAEd,MADA/X,QAAQ+X,MAAMA,GACR,IAAI1C,MAAM0C,EACjB,CAED,IAAIzX,EAAiB,GACjBC,EAAiB,GACjBI,EAAiB,GACjBoC,EAAkB,GAGtB7C,EAAS,qBACT,MAAM2C,EPjDH,SAAqByJ,GAC1B,MAAMhJ,cAAEA,EAAaiB,aAAEA,EAAYE,aAAEA,EAAYD,KAAEA,EAAIE,KAAEA,EAAInB,aAAEA,EAAYoB,WAAEA,GAAe2H,EAG5F,IAAIgP,EACkB,OAAlBhY,EACFgY,EAAO,IAAIvU,EAAO,CAAExC,eAAcC,OAAMjB,eAAcoB,eAC3B,OAAlBrB,EACTgY,EAAO,IAAI5T,EAAO,CAAEnD,eAAcC,OAAMC,eAAcC,OAAMnB,eAAcoB,eAE1ExE,EAAS,+CAIX,MAAMob,EAA+BD,EAAK1W,0BAA4B0W,EAAK3W,WAAa2W,EAAKrU,eAG7F,IAWIsD,EAAe3H,EAXfE,EAAoByY,EAA6BzY,kBACjD6E,EAAoB4T,EAA6B5T,kBACjDT,EAAcqU,EAA6BrU,YAC3CU,EAAc2T,EAA6B3T,YAC3CN,EAAMiU,EAA6BzW,eACnCa,EAAmB4V,EAA6B5V,iBAmBpD,OAhBqBhB,SAMnB4F,EAAgBjD,EAAI5H,OACpBkD,EAAaE,EAAkBpD,OAC/BI,EAAS,0BAA0ByK,kBAA8B3H,aAGjE2H,EAAgBhG,GAAkC,OAAlBjB,EAAyBmB,EAAe,GACxE7B,EAAasE,GAAiC,OAAlB5D,EAAyBsE,EAAc,GACnE9H,EAAS,2CAA2CyK,kBAA8B3H,YAG7E,CACLE,oBACA6E,oBACAT,cACAU,cACAN,MACA3B,mBACA4E,gBACA3H,aACAU,gBACAC,eAEJ,COJqBiY,CAAYhY,KAAK8I,YAClCpM,EAAS,8BAGT,MAAMmS,EAAmB,CACvBvP,kBAAmBD,EAASC,kBAC5B6E,kBAAmB9E,EAAS8E,mBAM9B,GAFAzH,EAAS,gCACTF,QAAQc,KAAK,oBACa,4BAAtB0C,KAAKuX,aAIP,GAHA7a,EAAS,iBAAiBsD,KAAKuX,gBAGL,YAAtBvX,KAAKnD,aAA4B,CACnCH,EAAS,+BAGTS,EADsB0L,EAAiB7I,KAAK8I,WAAY9I,KAAKP,oBAC9BtC,cACvC,KAAa,GAEFL,iBAAgBC,kBFjEpB,SAAsCsC,EAAUI,GACrD/C,EAAS,mDAGT,MAAM4C,kBACJA,EAAiB6E,kBACjBA,EAAiBL,IACjBA,EAAG3B,iBACHA,EAAgB4E,cAChBA,EAAajH,cACbA,EAAaC,aACbA,GACEV,EAGE2H,EAAU7B,EAAc9F,IACxBtC,eACJA,EAAcD,eACdA,EAAcyI,iBACdA,EAAgBF,eAChBA,EAAcJ,YACdA,EAAWC,aACXA,EAAYM,SACZA,GACEwB,EAGJ,IAAK,IAAIjD,EAAe,EAAGA,EAAegD,EAAehD,IAAgB,CAEvE,IAAK,IAAI8B,EAAiB,EAAGA,EAAiBL,EAAUK,IAEtDN,EAAiBM,GAAkB/B,EAAIC,GAAc8B,GAAkB,EAIzE,IAAK,IAAIoB,EAAmB,EAAGA,EAAmBhC,EAAY/I,OAAQ+K,IAEpE,GAAsB,OAAlBnH,EAAwB,CAE1B,IAAIoH,EAA+B7B,EAAepF,kBAAkBgF,EAAYgC,IAGhF,MAAME,EAAgB1B,EAA8B,CAClDrF,cAAe8G,EAA6B9G,cAC5CC,sBAAuB6G,EAA6B7G,sBACpDf,oBACAiG,mBACAC,cAIIM,YAAEA,EAAWC,oBAAEA,GAAwBoB,EAG7C,IAAK,IAAIE,EAAkB,EAAGA,EAAkB7B,EAAU6B,IAAmB,CAC3E,IAAII,EAAoBlC,EAAiB8B,GAGzC,IAAK,IAAIC,EAAkB,EAAGA,EAAkB9B,EAAU8B,IAAmB,CAC3E,IAAII,EAAoBnC,EAAiB+B,GACzCxK,EAAe2K,GAAmBC,KAC/BxC,EAAa+B,GACdnB,GACCC,EAAoBsB,GAAmBtB,EAAoBuB,GAC/D,CACF,CACF,MAEI,GAAsB,OAAlBxH,EACP,IAAK,IAAIyH,EAAmB,EAAGA,EAAmBtC,EAAY/I,OAAQqL,IAAoB,CAExF,IAAIL,EAA+B7B,EAAepF,kBAChDgF,EAAYgC,GACZhC,EAAYsC,IAId,MAAMJ,EAAgBnB,EAA8B,CAClD5F,cAAe8G,EAA6B9G,cAC5CC,sBAAuB6G,EAA6B7G,sBACpDC,sBAAuB4G,EAA6B5G,sBACpDhB,oBACA6E,oBACAoB,mBACAC,cAIIM,YAAEA,EAAWC,oBAAEA,EAAmBM,oBAAEA,GAAwBc,EAGlE,IAAK,IAAIE,EAAkB,EAAGA,EAAkB7B,EAAU6B,IAAmB,CAC3E,IAAII,EAAoBlC,EAAiB8B,GAGzC,IAAK,IAAIC,EAAkB,EAAGA,EAAkB9B,EAAU8B,IAAmB,CAC3E,IAAII,EAAoBnC,EAAiB+B,GACzCxK,EAAe2K,GAAmBC,KAC/BxC,EAAa+B,GACd/B,EAAaqC,GACbzB,GACCC,EAAoBsB,GAAmBtB,EAAoBuB,GAC1DjB,EAAoBgB,GAAmBhB,EAAoBiB,GAChE,CACF,CACF,CAGN,CAGD5K,EAAS,2CACT,MAAMub,EAA4B,IAAItQ,EACpClI,EACA0C,EACA2B,EACAhE,EACAC,GAIFkY,EAA0BnQ,mCACxB/K,EACAD,EACAmI,EACAC,EACA5F,EACA6E,EACAkB,GAEF3I,EAAS,0CAGTub,EAA0BrQ,qCAAqC7K,EAAgBD,GAC/EJ,EAAS,oDAGTJ,EAAS,2BACT,IAAK,IAAIL,EAAI,EAAGA,EAAIc,EAAeb,OAAQD,IACzCK,EAAS,QAAQL,MAAMc,EAAed,GAAG0D,cAAc,MAKzD,OAFAjD,EAAS,iDAEF,CACLI,iBACAC,iBAEJ,CEnF8Cmb,CACpC7Y,EACAW,KAAKP,qBAGPtC,EAD2BP,EAAkBoD,KAAKnD,aAAcC,EAAgBC,GAC5CI,cACrC,MACI,GAA0B,2BAAtB6C,KAAKuX,aAA2C,CACzD7a,EAAS,iBAAiBsD,KAAKuX,gBAG/B,IAAI7X,EAAwB,EAC5B,MAAMyY,EAA2B,EAG3BlZ,EAAU,CACdI,SAAUA,EACVI,mBAAoBO,KAAKP,mBACzBC,sBAAuBA,EACvB7C,aAAcmD,KAAKnD,aACnB0C,mBAGF,KAAOG,GAAyB,GAAG,CAEjCT,EAAQS,sBAAwBA,EAG5BvC,EAAejB,OAAS,IAC1B+C,EAAQM,gBAAkB,IAAIpC,IAIhC,MAAMib,EAAsBrZ,EAAc8H,EAA6B5H,EAAS,IAAK,MAGrFnC,EAAiBsb,EAAoBtb,eACrCC,EAAiBqb,EAAoBrb,eACrCI,EAAiBib,EAAoBjb,eAGrCuC,GAAyB,EAAIyY,CAC9B,CACF,CAID,OAHA3b,QAAQsC,QAAQ,oBAChBpC,EAAS,6BAEF,CAAES,iBAAgB0R,mBAC1B,2BCzHI,MAKL,WAAAhP,GACEG,KAAKqY,OAAS,KACdrY,KAAKsY,UAAY,KACjBtY,KAAKuY,SAAU,EAEfvY,KAAKwY,aACN,CAOD,iBAAMA,GACJ,IACExY,KAAKqY,OAAS,IAAII,OAAO,IAAIC,IAAI,qBAAsB,oBAAAC,SAAA,IAAAC,QAAA,OAAA,KAAA,QAAAC,YAAAC,KAAAH,SAAAI,eAAA,WAAAJ,SAAAI,cAAAC,QAAAC,eAAAN,SAAAI,cAAAG,KAAA,IAAAR,IAAA,mBAAAC,SAAAQ,SAAAL,MAAkB,CACvE/F,KAAM,WAGR/S,KAAKqY,OAAOe,QAAWC,IACrB7c,QAAQ+X,MAAM,iCAAkC8E,EAAM,EAExD,MAAMC,EAAgBC,EAAavZ,KAAKqY,QAExCrY,KAAKsY,gBAAkB,IAAIgB,EAE3BtZ,KAAKuY,SAAU,CAChB,CAAC,MAAOhE,GAEP,MADA/X,QAAQ+X,MAAM,8BAA+BA,GACvCA,CACP,CACF,CAQD,kBAAMiF,GACJ,OAAIxZ,KAAKuY,QAAgB1E,QAAQC,UAE1B,IAAID,SAAQ,CAACC,EAAS2F,KAC3B,IAAIC,EAAW,EACf,MAEMC,EAAa,KACjBD,IACI1Z,KAAKuY,QACPzE,IACS4F,GANO,GAOhBD,EAAO,IAAI5H,MAAM,2CAEjB+H,WAAWD,EAAY,IACxB,EAEHA,GAAY,GAEf,CAOD,qBAAMnC,CAAgBD,GAGpB,aAFMvX,KAAKwZ,eACX9c,EAAS,8CAA8C6a,KAChDvX,KAAKsY,UAAUd,gBAAgBD,EACvC,CAOD,mBAAME,CAAc3O,GAGlB,aAFM9I,KAAKwZ,eACX9c,EAAS,wCACFsD,KAAKsY,UAAUb,cAAc3O,EACrC,CAQD,0BAAM4O,CAAqBhR,EAAaiR,GAGtC,aAFM3X,KAAKwZ,eACX9c,EAAS,4DAA4DgK,KAC9D1G,KAAKsY,UAAUZ,qBAAqBhR,EAAaiR,EACzD,CAOD,qBAAMC,CAAgB/a,GAGpB,aAFMmD,KAAKwZ,eACX9c,EAAS,8CAA8CG,KAChDmD,KAAKsY,UAAUV,gBAAgB/a,EACvC,CAMD,WAAMgb,SACE7X,KAAKwZ,eACX9c,EAAS,uDAET,MAAMmd,EAAYC,YAAYC,MACxBC,QAAeha,KAAKsY,UAAUT,QAIpC,OADAnb,EAAS,4CAFOod,YAAYC,MAEmCF,GAAa,KAAMI,QAAQ,OACnFD,CACR,CAMD,kBAAME,GAEJ,aADMla,KAAKwZ,eACJxZ,KAAKsY,UAAU4B,cACvB,CAMD,UAAMC,GAEJ,aADMna,KAAKwZ,eACJxZ,KAAKsY,UAAU6B,MACvB,CAKD,SAAAC,GACMpa,KAAKqY,SACPrY,KAAKqY,OAAO+B,YACZpa,KAAKqY,OAAS,KACdrY,KAAKsY,UAAY,KACjBtY,KAAKuY,SAAU,EAElB,mBC9JoB,kCCGG8B,MAAOC,IAC/B,IAAIN,EAAS,CACX1a,kBAAmB,GACnB6E,kBAAmB,GACnB7C,eAAgB,CACdE,aAAc,GACdC,iBAAkB,IAEpBU,iBAAkB,GAClB1C,mBAAoB,GACpB6C,kBAAmB,CAAE,EACrBiY,MAAO,EACPC,OAAO,EACPC,SAAU,IACV/W,YAAa,EACbU,YAAa,EACblC,gBAAiB,GACjBN,aAAc,CAAE,GAId8Y,SADgBJ,EAAKK,QAEtBC,MAAM,MACNlP,KAAKmP,GAASA,EAAKC,SACnBC,QAAQF,GAAkB,KAATA,GAAwB,MAATA,IAE/BG,EAAU,GACVC,EAAY,EAEZC,EAAmB,EACnB9b,EAAa,EACb+b,EAAsB,EACtBC,EAAmB,CAAE5V,SAAU,GAC/B6V,EAAoB,EACpBC,EAAW,GACXC,EAA2B,EAE3BC,EAAsB,EAEtBC,EAAyB,EACzBC,EAAsB,CACxBC,IAAK,EACLjZ,IAAK,EACLkZ,YAAa,EACbC,YAAa,GAEXC,EAA2B,EAE3BC,EAAwB,CAAA,EAE5B,KAAOd,EAAYP,EAAMxe,QAAQ,CAC/B,MAAM2e,EAAOH,EAAMO,GAEnB,GAAa,gBAATJ,EAAwB,CAC1BG,EAAU,aACVC,IACA,QACN,CAAW,GAAa,mBAATJ,EAA2B,CACpCG,EAAU,GACVC,IACA,QACN,CAAW,GAAa,mBAATJ,EAA2B,CACpCG,EAAU,gBACVC,IACA,QACN,CAAW,GAAa,sBAATJ,EAA8B,CACvCG,EAAU,GACVC,IACA,QACN,CAAW,GAAa,cAATJ,EAAsB,CAC/BG,EAAU,WACVC,IACA,QACN,CAAW,GAAa,iBAATJ,EAAyB,CAClCG,EAAU,GACVC,IACA,QACN,CAAW,GAAa,WAATJ,EAAmB,CAC5BG,EAAU,QACVC,IACA,QACN,CAAW,GAAa,cAATJ,EAAsB,CAC/BG,EAAU,GACVC,IACA,QACN,CAAW,GAAa,cAATJ,EAAsB,CAC/BG,EAAU,WACVC,IACA,QACN,CAAW,GAAa,iBAATJ,EAAyB,CAClCG,EAAU,GACVC,IACA,QACD,CAED,MAAMe,EAAQnB,EAAKD,MAAM,OAAOG,QAAQkB,GAAkB,KAATA,IAEjD,GAAgB,eAAZjB,EACFhB,EAAOO,MAAQ2B,WAAWF,EAAM,IAChChC,EAAOQ,MAAqB,MAAbwB,EAAM,GACrBhC,EAAOS,SAAWuB,EAAM,QACnB,GAAgB,kBAAZhB,GACT,GAAIgB,EAAM9f,QAAU,EAAG,CACrB,IAAK,QAAQyW,KAAKqJ,EAAM,IAAK,CAC3Bf,IACA,QACD,CAED,MAAMxY,EAAY0Z,SAASH,EAAM,GAAI,IAC/BtZ,EAAMyZ,SAASH,EAAM,GAAI,IAC/B,IAAIlZ,EAAOkZ,EAAMpN,MAAM,GAAGtL,KAAK,KAC/BR,EAAOA,EAAKsZ,QAAQ,SAAU,IAE9BpC,EAAO9X,gBAAgBD,KAAK,CAC1BS,MACAD,YACAK,QAEH,OACI,GAAgB,UAAZkY,EAAqB,CAC9B,GAAyB,IAArBE,EAAwB,CAC1BA,EAAmBiB,SAASH,EAAM,GAAI,IACtC5c,EAAa+c,SAASH,EAAM,GAAI,IAChChC,EAAO1a,kBAAoB,IAAIjB,MAAMe,GAAYP,KAAK,GACtDmb,EAAO7V,kBAAoB,IAAI9F,MAAMe,GAAYP,KAAK,GACtDoc,IACA,QACD,CAED,GAAIE,EAAsBD,GAAkD,IAA9BE,EAAiB5V,SAAgB,CAC7E4V,EAAmB,CACjBO,IAAKQ,SAASH,EAAM,GAAI,IACxBtZ,IAAKyZ,SAASH,EAAM,GAAI,IACxBK,WAAYF,SAASH,EAAM,GAAI,IAC/BxW,SAAU2W,SAASH,EAAM,GAAI,KAG/BV,EAAW,GACXD,EAAoB,EACpBE,EAA2B,EAE3BN,IACA,QACD,CAED,GAAII,EAAoBD,EAAiB5V,SAAU,CACjD,IAAK,IAAIvJ,EAAI,EAAGA,EAAI+f,EAAM9f,QAAUmf,EAAoBD,EAAiB5V,SAAUvJ,IACjFqf,EAASrZ,KAAKka,SAASH,EAAM/f,GAAI,KACjCof,IAGF,GAAIA,EAAoBD,EAAiB5V,SAAU,CACjDyV,IACA,QACD,CAEDA,IACA,QACD,CAED,GAAIM,EAA2BH,EAAiB5V,SAAU,CACxD,MAAM8W,EAAUhB,EAASC,GAA4B,EAC/Cpd,EAAI+d,WAAWF,EAAM,IACrBO,EAAIL,WAAWF,EAAM,IAE3BhC,EAAO1a,kBAAkBgd,GAAWne,EACpC6b,EAAO7V,kBAAkBmY,GAAWC,EACpCvC,EAAOtW,cACPsW,EAAO5V,cAEPmX,IAEIA,IAA6BH,EAAiB5V,WAChD2V,IACAC,EAAmB,CAAE5V,SAAU,GAElC,CACP,MAAW,GAAgB,aAAZwV,EAAwB,CACjC,GAA4B,IAAxBQ,EAA2B,CAC7BA,EAAsBW,SAASH,EAAM,GAAI,IACzBG,SAASH,EAAM,GAAI,IACnCf,IACA,QACD,CAED,GAAIQ,EAAyBD,GAA2D,IAApCE,EAAoBG,YAAmB,CACzFH,EAAsB,CACpBC,IAAKQ,SAASH,EAAM,GAAI,IACxBtZ,IAAKyZ,SAASH,EAAM,GAAI,IACxBJ,YAAaO,SAASH,EAAM,GAAI,IAChCH,YAAaM,SAASH,EAAM,GAAI,KAGlChC,EAAOpY,aAAa8Z,EAAoBE,cACrC5B,EAAOpY,aAAa8Z,EAAoBE,cAAgB,GAAKF,EAAoBG,YAEpFC,EAA2B,EAC3Bb,IACA,QACD,CAED,GAAIa,EAA2BJ,EAAoBG,YAAa,CAC3CM,SAASH,EAAM,GAAI,IACtC,MAAMQ,EAAcR,EAAMpN,MAAM,GAAGlD,KAAK+Q,GAAQN,SAASM,EAAK,MAE9D,GAAwC,IAApCf,EAAoBE,aAAyD,IAApCF,EAAoBE,YAAmB,CAClF,MAAMc,EAAchB,EAAoBhZ,IAEnCqZ,EAAsBW,KACzBX,EAAsBW,GAAe,IAGvCX,EAAsBW,GAAaza,KAAKua,GAGnCxC,EAAO1X,kBAAkBoa,KAC5B1C,EAAO1X,kBAAkBoa,GAAe,IAE1C1C,EAAO1X,kBAAkBoa,GAAaza,KAAKua,EACrD,MAAuD,IAApCd,EAAoBE,YAE7B5B,EAAO1Y,eAAeG,iBAAiBQ,KAAKua,IACC,IAApCd,EAAoBE,aAGgB,KAApCF,EAAoBE,cAD7B5B,EAAO1Y,eAAeE,aAAaS,KAAKua,GAM1CV,IAEIA,IAA6BJ,EAAoBG,cACnDJ,IACAC,EAAsB,CAAEG,YAAa,GAExC,CACF,CAEDZ,GACD,CAuBD,OApBAjB,EAAO9X,gBAAgBK,SAASC,IAC9B,GAAuB,IAAnBA,EAAKC,UAAiB,CACxB,MAAMka,EAAgBZ,EAAsBvZ,EAAKE,MAAQ,GAErDia,EAAczgB,OAAS,GACzB8d,EAAOva,mBAAmBwC,KAAK,CAC7Ba,KAAMN,EAAKM,KACXJ,IAAKF,EAAKE,IACVka,MAAOD,GAGZ,KAGHrgB,EACE,+CAA+CoF,KAAKC,UAClDqY,EAAO1X,2FAIJ0X,CAAM,oBjBxQR,SAAmB6C,GACV,UAAVA,GAA+B,UAAVA,GACvBrgB,QAAQC,IACN,+BAAiCogB,EAAQ,yBACzC,sCAEFxgB,EAAkB,UAElBA,EAAkBwgB,EAClBngB,EAAS,qBAAqBmgB,KAElC,uBkBRO,SACL1f,EACA0R,EACA0I,EACAzX,EACAgd,EACAC,EACAC,EAAW,cAEX,MAAM1d,kBAAEA,EAAiB6E,kBAAEA,GAAsB0K,EAEjD,GAAsB,OAAlB/O,GAAuC,SAAbgd,EAAqB,CAEjD,IAAIG,EAEFA,EADE9f,EAAejB,OAAS,GAAKmC,MAAMkD,QAAQpE,EAAe,IACpDA,EAAeuO,KAAKoL,GAAQA,EAAI,KAEhC3Z,EAEV,IAAI+f,EAAQ7e,MAAM8e,KAAK7d,GAEnB8d,EAAW,CACbjf,EAAG+e,EACHX,EAAGU,EACHI,KAAM,QACNtK,KAAM,UACN8H,KAAM,CAAEyC,MAAO,mBAAoBC,MAAO,GAC1Cza,KAAM,YAGJ0a,EAAiBrhB,KAAKshB,IAAIC,OAAOC,WAAY,KAC7CC,EAAezhB,KAAKuC,OAAOwe,GAC3BW,EAAaL,EAAiBI,EAI9BE,EAAS,CACXC,MAAO,eAAexG,IACtBgG,MALcphB,KAAKuC,IAAImf,EAAaD,EAAc,KAMlDI,OALe,IAMfC,MAAO,CAAEF,MAAO,KAChBG,MAAO,CAAEH,MAAO,YAChBI,OAAQ,CAAEpU,EAAG,GAAIkM,EAAG,GAAImI,EAAG,GAAIxO,EAAG,KAGpCyO,OAAOC,QAAQvB,EAAW,CAACK,GAAWU,EAAQ,CAAES,YAAY,GAC7D,MAAM,GAAsB,OAAlBze,GAAuC,YAAbgd,EAAwB,CAE3D,MAAM0B,EAA4B,eAAbxB,EAGfyB,EAAgB,IAAIC,IAAIpf,GAAmBqf,KAC3CC,EAAgB,IAAIF,IAAIva,GAAmBwa,KAGjD,IAAIE,EAEFA,EADExgB,MAAMkD,QAAQpE,EAAe,IACrBA,EAAeuO,KAAIoF,GAAOA,EAAI,KAE9B3T,EAIZ,IAAIqgB,EAAiBrhB,KAAKshB,IAAIC,OAAOC,WAAY,KAC7C3c,EAAO7E,KAAKuC,OAAOY,GAEnBwf,EADO3iB,KAAKuC,OAAOyF,GACEnD,EACrB+d,EAAY5iB,KAAKshB,IAAID,EAAgB,KAIrCM,EAAS,CACXC,MAAO,GAAGjB,YAAmBvF,IAC7BgG,MAAOwB,EACPf,OANee,EAAYD,EAAc,GAOzCb,MAAO,CAAEF,MAAO,KAChBG,MAAO,CAAEH,MAAO,KAChBI,OAAQ,CAAEpU,EAAG,GAAIkM,EAAG,GAAImI,EAAG,GAAIxO,EAAG,IAClCoP,UAAW,WAGb,GAAIR,EAAc,CAEhB,MAAMS,EAAYR,EACZS,EAAYN,EAGSphB,KAAK2hB,QAAQ9gB,MAAM8e,KAAK7d,GAAoB,CAAC2f,EAAWC,IACnF,IAAIE,EAAuB5hB,KAAK2hB,QAAQ9gB,MAAM8e,KAAKhZ,GAAoB,CAAC8a,EAAWC,IAG/EG,EAAmB7hB,KAAK2hB,QAAQ9gB,MAAM8e,KAAKhgB,GAAiB,CAAC8hB,EAAWC,IAGxEI,EAAqB9hB,KAAK+hB,UAAUF,GAGpCG,EAAmB,GACvB,IAAK,IAAIvjB,EAAI,EAAGA,EAAIgjB,EAAYC,EAAWjjB,GAAKijB,EAAW,CACzD,IAAIO,EAASngB,EAAkBrD,GAC/BujB,EAAiBvd,KAAKwd,EACvB,CAGD,IAAIC,EAAc,CAChBC,EAAGL,EACHvM,KAAM,UACN6M,SAAU,CACRC,SAAU,UACVC,YAAY,GAGdC,SAAU,CACRhC,MAAO,YAET5f,EAAGqhB,EACHjD,EAAG6C,EAAqB,GACxBtc,KAAM,kBAIRub,OAAOC,QAAQvB,EAAW,CAAC2C,GAAc5B,EAAQ,CAAES,YAAY,GACrE,KAAW,CAEL,IAAImB,EAAc,CAChBvhB,EAAGmB,EACHid,EAAGpY,EACHwb,EAAGd,EACH9L,KAAM,UACN6M,SAAU,CACRC,SAAU,UACVC,YAAY,GAGdC,SAAU,CACRhC,MAAO,YAETjb,KAAM,kBAIRub,OAAOC,QAAQvB,EAAW,CAAC2C,GAAc5B,EAAQ,CAAES,YAAY,GAChE,CACF,CACH,uBlBzGOlE,iBACL3d,EAAS,oDACT,IACE,MAAMsjB,QAAuBC,MAAM,iEAC7BC,QAAmBF,EAAeG,OAClCC,EAAmB,IAAIC,KAAKH,EAAWI,OAAOC,UAAUC,MAAMC,iBAEpE,OADA/jB,EAAS,4BAA4B0jB,KAC9BA,CACR,CAAC,MAAO7L,GAEP,OADA5X,EAAS,wCAA0C4X,GAC5C,iCACR,CACH"} \ No newline at end of file diff --git a/dist/feascript.esm.js b/dist/feascript.esm.js index d0a9c3a..3bc5b62 100644 --- a/dist/feascript.esm.js +++ b/dist/feascript.esm.js @@ -1,7 +1,7 @@ -function e(e){let t=0;for(let n=0;n100){i(`Solution not converged. Error norm: ${l}`);break}m++}return{solutionVector:u,converged:d,iterations:m,jacobianMatrix:c,residualVector:f,nodesCoordinates:p}}class d{constructor(e,t,n,s,o){this.boundaryConditions=e,this.boundaryElements=t,this.nop=n,this.meshDimension=s,this.elementOrder=o}imposeConstantValueBoundaryConditions(e,t){o("Applying constant value boundary conditions (Dirichlet type)"),"1D"===this.meshDimension?Object.keys(this.boundaryConditions).forEach((n=>{if("constantValue"===this.boundaryConditions[n][0]){const o=this.boundaryConditions[n][1];s(`Boundary ${n}: Applying constant value of ${o} (Dirichlet condition)`),this.boundaryElements[n].forEach((([n,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[n][i]-1;s(` - Applied constant value to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=o;for(let n=0;n{const r=this.nop[n][i]-1;s(` - Applied constant value to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=o;for(let n=0;n{if("constantValue"===this.boundaryConditions[n][0]){const o=this.boundaryConditions[n][1];s(`Boundary ${n}: Applying constant value of ${o} (Dirichlet condition)`),this.boundaryElements[n].forEach((([n,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[n][i]-1;s(` - Applied constant value to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=o;for(let n=0;n{const r=this.nop[n][i]-1;s(` - Applied constant value to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=o;for(let n=0;n0&&void 0===this.parsedMesh.boundaryElements[0]){const e=[];for(let t=1;t{if(1===e.dimension){const t=this.parsedMesh.boundaryNodePairs[e.tag]||[];t.length>0&&(this.parsedMesh.boundaryElements[e.tag]||(this.parsedMesh.boundaryElements[e.tag]=[]),t.forEach((t=>{const n=t[0],o=t[1];s(`Processing boundary node pair: [${n}, ${o}] for boundary ${e.tag} (${e.name||"unnamed"})`);let r=!1;for(let t=0;t0&&void 0===this.parsedMesh.boundaryElements[0])){const e=[];for(let t=1;t{if("constantTemp"===this.boundaryConditions[n][0]){const o=this.boundaryConditions[n][1];s(`Boundary ${n}: Applying constant temperature of ${o} K (Dirichlet condition)`),this.boundaryElements[n].forEach((([n,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[n][i]-1;s(` - Applied constant temperature to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=o;for(let n=0;n{const r=this.nop[n][i]-1;s(` - Applied constant temperature to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=o;for(let n=0;n{if("constantTemp"===this.boundaryConditions[n][0]){const o=this.boundaryConditions[n][1];s(`Boundary ${n}: Applying constant temperature of ${o} K (Dirichlet condition)`),this.boundaryElements[n].forEach((([n,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[n][i]-1;s(` - Applied constant temperature to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=o;for(let n=0;n{const r=this.nop[n][i]-1;s(` - Applied constant temperature to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=o;for(let n=0;n{const t=this.boundaryConditions[e];"convection"===t[0]&&(d[e]=t[1],m[e]=t[2])})),"1D"===this.meshDimension?Object.keys(this.boundaryConditions).forEach((n=>{if("convection"===this.boundaryConditions[n][0]){const o=d[n],i=m[n];s(`Boundary ${n}: Applying convection with heat transfer coefficient h=${o} W/(m²·K) and external temperature T∞=${i} K`),this.boundaryElements[n].forEach((([n,r])=>{let a;"linear"===this.elementOrder?a=0===r?0:1:"quadratic"===this.elementOrder&&(a=0===r?0:2);const l=this.nop[n][a]-1;s(` - Applied convection boundary condition to node ${l+1} (element ${n+1}, local node ${a+1})`),e[l]+=-o*i,t[l][l]+=o}))}})):"2D"===this.meshDimension&&Object.keys(this.boundaryConditions).forEach((o=>{if("convection"===this.boundaryConditions[o][0]){const h=d[o],u=m[o];s(`Boundary ${o}: Applying convection with heat transfer coefficient h=${h} W/(m²·K) and external temperature T∞=${u} K`),this.boundaryElements[o].forEach((([o,d])=>{if("linear"===this.elementOrder){let m,c,f,p,g;0===d?(m=n[0],c=0,f=0,p=3,g=2):1===d?(m=0,c=n[0],f=0,p=2,g=1):2===d?(m=n[0],c=1,f=1,p=4,g=2):3===d&&(m=1,c=n[0],f=2,p=4,g=1);let y=l.getBasisFunctions(m,c),b=y.basisFunction,E=y.basisFunctionDerivKsi,$=y.basisFunctionDerivEta,M=0,v=0,C=0,w=0;const N=this.nop[o].length;for(let e=0;e0&&(i.initialSolution=[...n]);const o=l(p,i,100,1e-4);e=o.jacobianMatrix,t=o.residualVector,d=o.nodesCoordinates,n=o.solutionVector,s+=.2}}return console.timeEnd("totalSolvingTime"),o("Solving process completed"),{solutionVector:n,nodesCoordinates:d}}}const b=async e=>{let t={nodesXCoordinates:[],nodesYCoordinates:[],nodalNumbering:{quadElements:[],triangleElements:[]},boundaryElements:[],boundaryConditions:[],boundaryNodePairs:{},gmshV:0,ascii:!1,fltBytes:"8",totalNodesX:0,totalNodesY:0,physicalPropMap:[],elementTypes:{}},n=(await e.text()).split("\n").map((e=>e.trim())).filter((e=>""!==e&&" "!==e)),o="",i=0,r=0,a=0,l=0,d={numNodes:0},m=0,h=[],u=0,c=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},g=0,y={};for(;i""!==e));if("meshFormat"===o)t.gmshV=parseFloat(s[0]),t.ascii="0"===s[1],t.fltBytes=s[2];else if("physicalNames"===o){if(s.length>=3){if(!/^\d+$/.test(s[0])){i++;continue}const e=parseInt(s[0],10),n=parseInt(s[1],10);let o=s.slice(2).join(" ");o=o.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:n,dimension:e,name:o})}}else if("nodes"===o){if(0===r){r=parseInt(s[0],10),a=parseInt(s[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;y[n]||(y[n]=[]),y[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);g++,g===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=y[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),s(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t};function E(e,t,n,s,o,i,r="structured"){const{nodesXCoordinates:a,nodesYCoordinates:l}=t;if("1D"===s&&"line"===o){let t;t=e.length>0&&Array.isArray(e[0])?e.map((e=>e[0])):e;let s=Array.from(a),o={x:s,y:t,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},r=Math.min(window.innerWidth,700),l=Math.max(...s),d=r/l,m={title:`line plot - ${n}`,width:Math.max(d*l,400),height:350,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:70,r:40,t:50,b:50}};Plotly.newPlot(i,[o],m,{responsive:!0})}else if("2D"===s&&"contour"===o){const t="structured"===r,s=new Set(a).size,d=new Set(l).size;let m;m=Array.isArray(e[0])?e.map((e=>e[0])):e;let h=Math.min(window.innerWidth,700),u=Math.max(...a),c=Math.max(...l)/u,f=Math.min(h,600),p={title:`${o} plot - ${n}`,width:f,height:f*c*.8,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"};if(t){const t=s,n=d;math.reshape(Array.from(a),[t,n]);let o=math.reshape(Array.from(l),[t,n]),r=math.reshape(Array.from(e),[t,n]),m=math.transpose(r),h=[];for(let e=0;e100){i(`Solution not converged. Error norm: ${l}`);break}c++}return{solutionVector:h,converged:d,iterations:c,jacobianMatrix:m,residualVector:f}}class d{constructor({meshDimension:e,elementOrder:t}){this.meshDimension=e,this.elementOrder=t}getBasisFunctions(e,t=null){let n=[],o=[],s=[];if("1D"===this.meshDimension)"linear"===this.elementOrder?(n[0]=1-e,n[1]=e,o[0]=-1,o[1]=1):"quadratic"===this.elementOrder&&(n[0]=1-3*e+2*e**2,n[1]=4*e-4*e**2,n[2]=2*e**2-e,o[0]=4*e-3,o[1]=4-8*e,o[2]=4*e-1);else if("2D"===this.meshDimension){if(null===t)return void i("Eta coordinate is required for 2D elements");if("linear"===this.elementOrder){function r(e){return 1-e}n[0]=r(e)*r(t),n[1]=r(e)*t,n[2]=e*r(t),n[3]=e*t,o[0]=-1*r(t),o[1]=-1*t,o[2]=1*r(t),o[3]=1*t,s[0]=-1*r(e),s[1]=1*r(e),s[2]=-1*e,s[3]=1*e}else if("quadratic"===this.elementOrder){function a(e){return 2*e**2-3*e+1}function l(e){return-4*e**2+4*e}function d(e){return 2*e**2-e}function c(e){return 4*e-3}function u(e){return-8*e+4}function h(e){return 4*e-1}n[0]=a(e)*a(t),n[1]=a(e)*l(t),n[2]=a(e)*d(t),n[3]=l(e)*a(t),n[4]=l(e)*l(t),n[5]=l(e)*d(t),n[6]=d(e)*a(t),n[7]=d(e)*l(t),n[8]=d(e)*d(t),o[0]=c(e)*a(t),o[1]=c(e)*l(t),o[2]=c(e)*d(t),o[3]=u(e)*a(t),o[4]=u(e)*l(t),o[5]=u(e)*d(t),o[6]=h(e)*a(t),o[7]=h(e)*l(t),o[8]=h(e)*d(t),s[0]=a(e)*c(t),s[1]=a(e)*u(t),s[2]=a(e)*h(t),s[3]=l(e)*c(t),s[4]=l(e)*u(t),s[5]=l(e)*h(t),s[6]=d(e)*c(t),s[7]=d(e)*u(t),s[8]=d(e)*h(t)}}return{basisFunction:n,basisFunctionDerivKsi:o,basisFunctionDerivEta:s}}}class c{constructor({numElementsX:e=null,maxX:t=null,numElementsY:n=null,maxY:o=null,meshDimension:i=null,elementOrder:r="linear",parsedMesh:a=null}){this.numElementsX=e,this.numElementsY=n,this.maxX=t,this.maxY=o,this.meshDimension=i,this.elementOrder=r,this.parsedMesh=a,this.boundaryElementsProcessed=!1,this.parsedMesh&&(s("Using pre-parsed mesh from gmshReader data for mesh generation."),this.parseMeshFromGmsh())}parseMeshFromGmsh(){if(this.parsedMesh.nodalNumbering||i("No valid nodal numbering found in the parsed mesh."),"object"==typeof this.parsedMesh.nodalNumbering&&!Array.isArray(this.parsedMesh.nodalNumbering)){const e=this.parsedMesh.nodalNumbering.quadElements||[];if(this.parsedMesh.nodalNumbering.triangleElements,o("Initial parsed mesh nodal numbering from GMSH format: "+JSON.stringify(this.parsedMesh.nodalNumbering)),this.parsedMesh.elementTypes[3]||this.parsedMesh.elementTypes[10]){const t=[];for(let n=0;n0&&void 0===this.parsedMesh.boundaryElements[0]){const e=[];for(let t=1;t{if(1===e.dimension){const t=this.parsedMesh.boundaryNodePairs[e.tag]||[];t.length>0&&(this.parsedMesh.boundaryElements[e.tag]||(this.parsedMesh.boundaryElements[e.tag]=[]),t.forEach((t=>{const n=t[0],s=t[1];o(`Processing boundary node pair: [${n}, ${s}] for boundary ${e.tag} (${e.name||"unnamed"})`);let r=!1;for(let t=0;t0&&void 0===this.parsedMesh.boundaryElements[0])){const e=[];for(let t=1;t{if("constantValue"===this.boundaryConditions[n][0]){const s=this.boundaryConditions[n][1];o(`Boundary ${n}: Applying constant value of ${s} (Dirichlet condition)`),this.boundaryElements[n].forEach((([n,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[n][i]-1;o(` - Applied constant value to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[n][i]-1;o(` - Applied constant value to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantValue"===this.boundaryConditions[n][0]){const s=this.boundaryConditions[n][1];o(`Boundary ${n}: Applying constant value of ${s} (Dirichlet condition)`),this.boundaryElements[n].forEach((([n,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[n][i]-1;o(` - Applied constant value to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[n][i]-1;o(` - Applied constant value to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantTemp"===this.boundaryConditions[n][0]){const s=this.boundaryConditions[n][1];o(`Boundary ${n}: Applying constant temperature of ${s} K (Dirichlet condition)`),this.boundaryElements[n].forEach((([n,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[n][i]-1;o(` - Applied constant temperature to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[n][i]-1;o(` - Applied constant temperature to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantTemp"===this.boundaryConditions[n][0]){const s=this.boundaryConditions[n][1];o(`Boundary ${n}: Applying constant temperature of ${s} K (Dirichlet condition)`),this.boundaryElements[n].forEach((([n,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[n][i]-1;o(` - Applied constant temperature to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[n][i]-1;o(` - Applied constant temperature to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const t=this.boundaryConditions[e];"convection"===t[0]&&(d[e]=t[1],c[e]=t[2])})),"1D"===this.meshDimension?Object.keys(this.boundaryConditions).forEach((n=>{if("convection"===this.boundaryConditions[n][0]){const s=d[n],i=c[n];o(`Boundary ${n}: Applying convection with heat transfer coefficient h=${s} W/(m²·K) and external temperature T∞=${i} K`),this.boundaryElements[n].forEach((([n,r])=>{let a;"linear"===this.elementOrder?a=0===r?0:1:"quadratic"===this.elementOrder&&(a=0===r?0:2);const l=this.nop[n][a]-1;o(` - Applied convection boundary condition to node ${l+1} (element ${n+1}, local node ${a+1})`),e[l]+=-s*i,t[l][l]+=s}))}})):"2D"===this.meshDimension&&Object.keys(this.boundaryConditions).forEach((s=>{if("convection"===this.boundaryConditions[s][0]){const u=d[s],h=c[s];o(`Boundary ${s}: Applying convection with heat transfer coefficient h=${u} W/(m²·K) and external temperature T∞=${h} K`),this.boundaryElements[s].forEach((([s,d])=>{if("linear"===this.elementOrder){let c,m,f,p,y;0===d?(c=n[0],m=0,f=0,p=3,y=2):1===d?(c=0,m=n[0],f=0,p=2,y=1):2===d?(c=n[0],m=1,f=1,p=4,y=2):3===d&&(c=1,m=n[0],f=2,p=4,y=1);let g=l.getBasisFunctions(c,m),b=g.basisFunction,E=g.basisFunctionDerivKsi,v=g.basisFunctionDerivEta,M=0,$=0,x=0,C=0;const F=this.nop[s].length;for(let e=0;e{if("constantTemp"===t[e][0]){const n=t[e][1];switch(e){case"0":for(let e=0;eArray(x).fill(0))),u=Array($).fill(0),h=Array($).fill(0),m=Array($).fill(0),f=1;A.iwr1++;let p=1,y=1;D.nell=0;for(let e=0;ex||g>x)return void i("Error: nmax-nsum not large enough");for(let e=0;e0)for(let e=0;e<$;e++){let t=l[e]-1,n=Math.abs(s[t]);for(let e=0;ey||D.nellMath.abs(l)&&(l=i,n=o,t=s)}}}let m=Math.abs(s[t-1]);e=Math.abs(w.lhed[n-1]);let y=m+e+u[m-1]+h[e-1];A.det=A.det*l*(-1)**y/Math.abs(l);for(let t=0;t=m&&u[t]--,t>=e&&h[t]--;if(Math.abs(l)<1e-10&&i(`Warning: matrix singular or ill-conditioned, nell=${D.nell}, kro=${m}, lco=${e}, pivot=${l}`),0===l)return;for(let e=0;e1)for(let e=0;e1&&0!==o)for(let t=0;t1)for(let t=0;t1||D.nellArray(9).fill(0))),xpt:Array($).fill(0),ypt:Array($).fill(0),ncod:Array($).fill(0),bc:Array($).fill(0),r1:Array($).fill(0),u:Array($).fill(0),ntop:Array(M).fill(0),nlat:Array(M).fill(0)},F={w:[.27777777777778,.444444444444,.27777777777778],gp:[.1127016654,.5,.8872983346]},A={iwr1:0,npt:0,ntra:0,nbn:Array(M).fill(0),det:1,sk:Array(x*x).fill(0),ice1:0},D={estifm:Array(9).fill().map((()=>Array(9).fill(0))),nell:0},w={ecv:Array(2e6).fill(0),lhed:Array(x).fill(0),qq:Array(x).fill(0),ecpiv:Array(2e6).fill(0)},N=new d({meshDimension:"2D",elementOrder:"quadratic"});function O(){const e=D.nell-1,{estifm:t,localLoad:n,ngl:o}=function({elementIndex:e,nop:t,xCoordinates:n,yCoordinates:o,basisFunctions:s,gaussPoints:i,gaussWeights:r,ntopFlag:a=!1,nlatFlag:l=!1,convectionTop:d={active:!1,coeff:0,extTemp:0}}){const c=Array(9).fill().map((()=>Array(9).fill(0))),u=Array(9).fill(0),h=Array(9);for(let n=0;n<9;n++)h[n]=Math.abs(t[e][n]);for(let e=0;ee-1)),{detJacobian:m,basisFunctionDerivX:f,basisFunctionDerivY:p}=y({basisFunction:a,basisFunctionDerivKsi:l,basisFunctionDerivEta:d,nodesXCoordinates:n,nodesYCoordinates:o,localToGlobalMap:u,numNodes:9});for(let n=0;n<9;n++)for(let o=0;o<9;o++)c[n][o]-=r[e]*r[t]*m*(f[n]*f[o]+p[n]*p[o])}if(a&&d.active){const a=d.coeff,l=d.extTemp;for(let d=0;d0)continue;let r=0;w.qq[s-1]=0;for(let e=0;e0&&(a.initialSolution=[...n]);const s=l(b,a,100,1e-4);e=s.jacobianMatrix,t=s.residualVector,n=s.solutionVector,o+=1/i}}return console.timeEnd("totalSolvingTime"),s("Solving process completed"),{solutionVector:n,nodesCoordinates:c}}}const k=async e=>{let t={nodesXCoordinates:[],nodesYCoordinates:[],nodalNumbering:{quadElements:[],triangleElements:[]},boundaryElements:[],boundaryConditions:[],boundaryNodePairs:{},gmshV:0,ascii:!1,fltBytes:"8",totalNodesX:0,totalNodesY:0,physicalPropMap:[],elementTypes:{}},n=(await e.text()).split("\n").map((e=>e.trim())).filter((e=>""!==e&&" "!==e)),s="",i=0,r=0,a=0,l=0,d={numNodes:0},c=0,u=[],h=0,m=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},y=0,g={};for(;i""!==e));if("meshFormat"===s)t.gmshV=parseFloat(o[0]),t.ascii="0"===o[1],t.fltBytes=o[2];else if("physicalNames"===s){if(o.length>=3){if(!/^\d+$/.test(o[0])){i++;continue}const e=parseInt(o[0],10),n=parseInt(o[1],10);let s=o.slice(2).join(" ");s=s.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:n,dimension:e,name:s})}}else if("nodes"===s){if(0===r){r=parseInt(o[0],10),a=parseInt(o[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;g[n]||(g[n]=[]),g[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);y++,y===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=g[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),o(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t};function T(e,t,n,o,s,i,r="structured"){const{nodesXCoordinates:a,nodesYCoordinates:l}=t;if("1D"===o&&"line"===s){let t;t=e.length>0&&Array.isArray(e[0])?e.map((e=>e[0])):e;let o=Array.from(a),s={x:o,y:t,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},r=Math.min(window.innerWidth,700),l=Math.max(...o),d=r/l,c={title:`line plot - ${n}`,width:Math.max(d*l,400),height:350,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:70,r:40,t:50,b:50}};Plotly.newPlot(i,[s],c,{responsive:!0})}else if("2D"===o&&"contour"===s){const t="structured"===r,o=new Set(a).size,d=new Set(l).size;let c;c=Array.isArray(e[0])?e.map((e=>e[0])):e;let u=Math.min(window.innerWidth,700),h=Math.max(...a),m=Math.max(...l)/h,f=Math.min(u,600),p={title:`${s} plot - ${n}`,width:f,height:f*m*.8,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"};if(t){const t=o,n=d;math.reshape(Array.from(a),[t,n]);let s=math.reshape(Array.from(l),[t,n]),r=math.reshape(Array.from(e),[t,n]),c=math.transpose(r),u=[];for(let e=0;e"object"==typeof e&&null!==e||"function"==typeof e,D=new Map([["proxy",{canHandle:e=>N(e)&&e[$],serialize(e){const{port1:t,port2:n}=new MessageChannel;return x(e,t),[n,[n]]},deserialize:e=>(e.start(),S(e))}],["throw",{canHandle:e=>N(e)&&w in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function x(e,t=globalThis,n=["*"]){t.addEventListener("message",(function s(o){if(!o||!o.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,o.origin))return void console.warn(`Invalid origin '${o.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},o.data),l=(o.data.argumentList||[]).map(W);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=W(o.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[$]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;x(e,n),d=function(e,t){return Y.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[w]:0}}Promise.resolve(d).catch((e=>({value:e,[w]:0}))).then((n=>{const[o,a]=R(n);t.postMessage(Object.assign(Object.assign({},o),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",s),O(t),C in e&&"function"==typeof e[C]&&e[C]())})).catch((e=>{const[n,s]=R({value:new TypeError("Unserializable return value"),[w]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),s)}))})),t.start&&t.start()}function O(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function S(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const s=n.get(t.id);if(s)try{s(t)}finally{n.delete(t.id)}})),T(e,n,[],t)}function A(e){if(e)throw new Error("Proxy has been released and is not useable")}function F(e){return B(e,new Map,{type:"RELEASE"}).then((()=>{O(e)}))}const X=new WeakMap,k="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(X.get(e)||0)-1;X.set(e,t),0===t&&F(e)}));function T(e,t,n=[],s=function(){}){let o=!1;const i=new Proxy(s,{get(s,r){if(A(o),r===v)return()=>{!function(e){k&&k.unregister(e)}(i),F(e),t.clear(),o=!0};if("then"===r){if(0===n.length)return{then:()=>i};const s=B(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(W);return s.then.bind(s)}return T(e,t,[...n,r])},set(s,i,r){A(o);const[a,l]=R(r);return B(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(W)},apply(s,i,r){A(o);const a=n[n.length-1];if(a===M)return B(e,t,{type:"ENDPOINT"}).then(W);if("bind"===a)return T(e,t,n.slice(0,-1));const[l,d]=P(r);return B(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(W)},construct(s,i){A(o);const[r,a]=P(i);return B(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(W)}});return function(e,t){const n=(X.get(t)||0)+1;X.set(t,n),k&&k.register(e,t,e)}(i,e),i}function P(e){const t=e.map(R);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const Y=new WeakMap;function R(e){for(const[t,n]of D)if(n.canHandle(e)){const[s,o]=n.serialize(e);return[{type:"HANDLER",name:t,value:s},o]}return[{type:"RAW",value:e},Y.get(e)||[]]}function W(e){switch(e.type){case"HANDLER":return D.get(e.name).deserialize(e.value);case"RAW":return e.value}}function B(e,t,n,s){return new Promise((o=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,o),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),s)}))}class I{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js",import.meta.url),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=S(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const s=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(s,1e3)};s()}))}async setSolverConfig(e){return await this._ensureReady(),o(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),o("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),o(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),o(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),o("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return o(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}}const q="0.1.3";export{y as FEAScriptModel,I as FEAScriptWorker,q as VERSION,b as importGmshQuadTri,n as logSystem,E as plotSolution,r as printVersion}; + */const q=Symbol("Comlink.proxy"),Y=Symbol("Comlink.endpoint"),P=Symbol("Comlink.releaseProxy"),W=Symbol("Comlink.finalizer"),R=Symbol("Comlink.thrown"),B=e=>"object"==typeof e&&null!==e||"function"==typeof e,I=new Map([["proxy",{canHandle:e=>B(e)&&e[q],serialize(e){const{port1:t,port2:n}=new MessageChannel;return j(e,t),[n,[n]]},deserialize:e=>(e.start(),G(e))}],["throw",{canHandle:e=>B(e)&&R in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function j(e,t=globalThis,n=["*"]){t.addEventListener("message",(function o(s){if(!s||!s.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,s.origin))return void console.warn(`Invalid origin '${s.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},s.data),l=(s.data.argumentList||[]).map(Z);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=Z(s.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[q]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;j(e,n),d=function(e,t){return H.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[R]:0}}Promise.resolve(d).catch((e=>({value:e,[R]:0}))).then((n=>{const[s,a]=Q(n);t.postMessage(Object.assign(Object.assign({},s),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",o),V(t),W in e&&"function"==typeof e[W]&&e[W]())})).catch((e=>{const[n,o]=Q({value:new TypeError("Unserializable return value"),[R]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),o)}))})),t.start&&t.start()}function V(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function G(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const o=n.get(t.id);if(o)try{o(t)}finally{n.delete(t.id)}})),U(e,n,[],t)}function K(e){if(e)throw new Error("Proxy has been released and is not useable")}function L(e){return ee(e,new Map,{type:"RELEASE"}).then((()=>{V(e)}))}const J=new WeakMap,z="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(J.get(e)||0)-1;J.set(e,t),0===t&&L(e)}));function U(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(K(s),r===P)return()=>{!function(e){z&&z.unregister(e)}(i),L(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=ee(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(Z);return o.then.bind(o)}return U(e,t,[...n,r])},set(o,i,r){K(s);const[a,l]=Q(r);return ee(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(Z)},apply(o,i,r){K(s);const a=n[n.length-1];if(a===Y)return ee(e,t,{type:"ENDPOINT"}).then(Z);if("bind"===a)return U(e,t,n.slice(0,-1));const[l,d]=_(r);return ee(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(Z)},construct(o,i){K(s);const[r,a]=_(i);return ee(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(Z)}});return function(e,t){const n=(J.get(t)||0)+1;J.set(t,n),z&&z.register(e,t,e)}(i,e),i}function _(e){const t=e.map(Q);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const H=new WeakMap;function Q(e){for(const[t,n]of I)if(n.canHandle(e)){const[o,s]=n.serialize(e);return[{type:"HANDLER",name:t,value:o},s]}return[{type:"RAW",value:e},H.get(e)||[]]}function Z(e){switch(e.type){case"HANDLER":return I.get(e.name).deserialize(e.value);case"RAW":return e.value}}function ee(e,t,n,o){return new Promise((s=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,s),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),o)}))}class te{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js",import.meta.url),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=G(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const o=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(o,1e3)};o()}))}async setSolverConfig(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),s("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),s(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),s("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return s(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}}const ne="0.1.3";export{X as FEAScriptModel,te as FEAScriptWorker,ne as VERSION,k as importGmshQuadTri,n as logSystem,T as plotSolution,r as printVersion}; //# sourceMappingURL=feascript.esm.js.map diff --git a/dist/feascript.esm.js.map b/dist/feascript.esm.js.map index ac76e61..9593b40 100644 --- a/dist/feascript.esm.js.map +++ b/dist/feascript.esm.js.map @@ -1 +1 @@ -{"version":3,"file":"feascript.esm.js","sources":["../src/methods/euclideanNormScript.js","../src/utilities/loggingScript.js","../src/methods/linearSystemSolverScript.js","../src/methods/jacobiSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/utilities/helperFunctionsScript.js","../src/solvers/genericBoundaryConditionsScript.js","../src/mesh/basisFunctionsScript.js","../src/mesh/meshGenerationScript.js","../src/methods/numericalIntegrationScript.js","../src/solvers/frontPropagationScript.js","../src/solvers/thermalBoundaryConditionsScript.js","../src/FEAScript.js","../src/solvers/solidHeatTransferScript.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.js","../src/vendor/comlink.mjs","../src/workers/workerScript.js","../src/index.js"],"sourcesContent":["// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to calculate the Euclidean norm of a vector\n * @param {array} vector - The input vector\n * @returns {number} The Euclidean norm of the vector\n */\nexport function euclideanNorm(vector) {\n let norm = 0;\n for (let i = 0; i < vector.length; i++) {\n norm += vector[i] * vector[i];\n }\n norm = Math.sqrt(norm);\n return norm;\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Global logging level\nlet currentLogLevel = \"basic\";\n\n/**\n * Function to set the logging system level\n * @param {string} level - Logging level (basic, debug)\n */\nexport function logSystem(level) {\n if (level !== \"basic\" && level !== \"debug\") {\n console.log(\n \"%c[WARN] Invalid log level: \" + level + \". Using basic instead.\",\n \"color: #FFC107; font-weight: bold;\"\n ); // Yellow for warnings\n currentLogLevel = \"basic\";\n } else {\n currentLogLevel = level;\n basicLog(`Log level set to: ${level}`);\n }\n}\n\n/**\n * Function to log debug messages - only logs if level is 'debug'\n * @param {string} message - Message to log\n */\nexport function debugLog(message) {\n if (currentLogLevel === \"debug\") {\n console.log(\"%c[DEBUG] \" + message, \"color: #2196F3; font-weight: bold;\"); // Blue color for debug\n }\n}\n\n/**\n * Function to log basic information - always logs\n * @param {string} message - Message to log\n */\nexport function basicLog(message) {\n console.log(\"%c[INFO] \" + message, \"color: #4CAF50; font-weight: bold;\"); // Green color for basic info\n}\n\n/**\n * Function to log error messages\n * @param {string} message - Message to log\n */\nexport function errorLog(message) {\n console.log(\"%c[ERROR] \" + message, \"color: #F44336; font-weight: bold;\"); // Red color for errors\n}\n\n/**\n * Function to handle version information and fetch the latest update date and release from GitHub\n */\nexport async function printVersion() {\n basicLog(\"Fetching latest FEAScript version information...\");\n try {\n const commitResponse = await fetch(\"https://api.github.com/repos/FEAScript/FEAScript/commits/main\");\n const commitData = await commitResponse.json();\n const latestCommitDate = new Date(commitData.commit.committer.date).toLocaleString();\n basicLog(`Latest FEAScript update: ${latestCommitDate}`);\n return latestCommitDate;\n } catch (error) {\n errorLog(\"Failed to fetch version information: \" + error);\n return \"Version information unavailable\";\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiSolver } from \"./jacobiSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to solve a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (\"lusolve\" or \"jacobi\")\n * @param {Array} jacobianMatrix - The coefficient matrix\n * @param {Array} residualVector - The right-hand side vector\n * @param {object} [options] - Additional options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum iterations for iterative methods\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance for iterative methods\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - converged: Boolean indicating whether the method converged (for iterative methods)\n * - iterations: Number of iterations performed (for iterative methods)\n */\nexport function solveLinearSystem(solverMethod, jacobianMatrix, residualVector, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n\n let solutionVector = [];\n let converged = true;\n let iterations = 0;\n\n // Solve the linear system based on the specified solver method\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n if (solverMethod === \"lusolve\") {\n // Use LU decomposition method\n solutionVector = math.lusolve(jacobianMatrix, residualVector);\n } else if (solverMethod === \"jacobi\") {\n // Use Jacobi method\n const initialGuess = new Array(residualVector.length).fill(0);\n const jacobiSolverResult = jacobiSolver(jacobianMatrix, residualVector, initialGuess, {\n maxIterations,\n tolerance,\n });\n\n // Log convergence information\n if (jacobiSolverResult.converged) {\n debugLog(`Jacobi method converged in ${jacobiSolverResult.iterations} iterations`);\n } else {\n debugLog(`Jacobi method did not converge after ${jacobiSolverResult.iterations} iterations`);\n }\n\n solutionVector = jacobiSolverResult.solutionVector;\n converged = jacobiSolverResult.converged;\n iterations = jacobiSolverResult.iterations;\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n return { solutionVector, converged, iterations };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method\n * @param {array} jacobianMatrix - The coefficient matrix (must be square)\n * @param {array} residualVector - The right-hand side vector\n * @param {array} initialGuess - Initial guess for solution vector\n * @param {object} [options] - Options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum number of iterations\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\nexport function jacobiSolver(jacobianMatrix, residualVector, initialGuess, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n const n = jacobianMatrix.length; // Size of the square matrix\n let x = [...initialGuess]; // Current solution (starts with initial guess)\n let xNew = new Array(n); // Next iteration's solution\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n // Perform one iteration\n for (let i = 0; i < n; i++) {\n let sum = 0;\n // Calculate sum of jacobianMatrix[i][j] * x[j] for j ≠ i\n for (let j = 0; j < n; j++) {\n if (j !== i) {\n sum += jacobianMatrix[i][j] * x[j];\n }\n }\n // Update xNew[i] using the Jacobi formula\n xNew[i] = (residualVector[i] - sum) / jacobianMatrix[i][i];\n }\n\n // Check convergence\n let maxDiff = 0;\n for (let i = 0; i < n; i++) {\n maxDiff = Math.max(maxDiff, Math.abs(xNew[i] - x[i]));\n }\n\n // Update x for next iteration\n x = [...xNew];\n\n // Successfully converged if maxDiff is less than tolerance\n if (maxDiff < tolerance) {\n return {\n solutionVector: x,\n iterations: iteration + 1,\n converged: true,\n };\n }\n }\n\n // maxIterations were reached without convergence\n return {\n solutionVector: x,\n iterations: maxIterations,\n converged: false,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { euclideanNorm } from \"../methods/euclideanNormScript.js\";\nimport { solveLinearSystem } from \"./linearSystemSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\nimport { calculateSystemSize } from \"../utilities/helperFunctionsScript.js\";\n\n/**\n * Function to solve a system of nonlinear equations using the Newton-Raphson method\n * @param {number} [maxIterations=100] - Maximum number of iterations\n * @param {number} [tolerance=1e-4] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\n\nexport function newtonRaphson(assembleMat, context, maxIterations = 100, tolerance = 1e-4) {\n let errorNorm = 0;\n let converged = false;\n let iterations = 0;\n let deltaX = [];\n let solutionVector = [];\n let jacobianMatrix = [];\n let residualVector = [];\n let nodesCoordinates = {};\n\n // Calculate system size directly from meshConfig\n let totalNodes = calculateSystemSize(context.meshConfig);\n\n // Initialize arrays with proper size\n for (let i = 0; i < totalNodes; i++) {\n deltaX[i] = 0;\n solutionVector[i] = 0;\n }\n\n // Initialize solution from context if available\n if (context.initialSolution && context.initialSolution.length === totalNodes) {\n solutionVector = [...context.initialSolution];\n }\n\n while (iterations < maxIterations && !converged) {\n // Update solution\n for (let i = 0; i < solutionVector.length; i++) {\n solutionVector[i] = Number(solutionVector[i]) + Number(deltaX[i]);\n }\n\n // Compute Jacobian and residual matrices\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleMat(\n context.meshConfig,\n context.boundaryConditions,\n solutionVector, // The solution vector is required in the case of a non-linear equation\n context.eikonalActivationFlag\n ));\n\n // Solve the linear system based on the specified solver method\n const linearSystemResult = solveLinearSystem(context.solverMethod, jacobianMatrix, residualVector);\n deltaX = linearSystemResult.solutionVector;\n\n // Check convergence\n errorNorm = euclideanNorm(deltaX);\n\n // Norm for each iteration\n basicLog(`Newton-Raphson iteration ${iterations + 1}: Error norm = ${errorNorm.toExponential(4)}`);\n\n if (errorNorm <= tolerance) {\n converged = true;\n } else if (errorNorm > 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n nodesCoordinates,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Helper function to calculate system size from mesh configuration\n * @param {object} meshConfig - Mesh configuration object\n * @returns {number} Total number of nodes in the system\n */\nexport function calculateSystemSize(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, elementOrder, parsedMesh } = meshConfig;\n\n if (parsedMesh && parsedMesh.nodesXCoordinates) {\n // For parsed meshes (like from GMSH)\n return parsedMesh.nodesXCoordinates.length;\n } else {\n // For geometry-based meshes\n let nodesX,\n nodesY = 1;\n\n if (elementOrder === \"linear\") {\n nodesX = numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = numElementsY + 1;\n } else if (elementOrder === \"quadratic\") {\n nodesX = 2 * numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = 2 * numElementsY + 1;\n }\n\n return nodesX * nodesY;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n debugLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n if (\n this.numElementsX === null ||\n this.maxX === null ||\n this.numElementsY === null ||\n this.maxY === null\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n \n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\n\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the front propagation matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation (ranges from 0 to 1)\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleFrontPropagationMat(\n meshConfig,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n // TODO: The mesh generation step should be moved outside of the assembleFrontPropagationMat function so that not performed in every Newton-Raphson iteration\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n let solutionDerivX; // The x-derivative of the solution\n let solutionDerivY; // The y-derivative of the solution\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n detJacobian = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n detJacobian = ksiDerivX;\n }\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n // 2D front propagation (eikonal) equation\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n solutionDerivX = 0;\n solutionDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x & y-derivatives of basis functions and x & y-derivatives of the solution\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n // The x-derivative of the solution\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n // The y-derivative of the solution\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector - Viscous term: Add diffusion contribution to stabilize the solution\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n // residualVector - Eikonal term: Add the eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix - Viscous term: Add the Jacobian contribution from the diffusion term\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n // jacobianMatrix - Eikonal term: Add the Jacobian contribution from the eikonal equation\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n (detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)\n ) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n }\n\n // Create an instance of GenericBoundaryConditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions (Robin type)\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n let nodesCoordinates = {};\n let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term - Used in frontPropagationScript\n let newtonRaphsonIterations;\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleSolidHeatTransferMat(\n this.meshConfig,\n this.boundaryConditions\n ));\n\n // Solve the assembled linear system\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n\n // Create context object with all necessary properties\n const context = {\n meshConfig: this.meshConfig,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n nodesCoordinates = newtonRaphsonResult.nodesCoordinates;\n solutionVector = newtonRaphsonResult.solutionVector;\n newtonRaphsonIterations = newtonRaphsonResult.iterations;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the solid heat transfer matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n // 2D solid heat transfer\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Create an instance of ThermalBoundaryConditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.3\";"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","logSystem","level","console","log","basicLog","debugLog","message","errorLog","async","printVersion","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString","error","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","math","lusolve","jacobiSolverResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiSolver","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","nodesCoordinates","totalNodes","meshConfig","meshDimension","numElementsX","numElementsY","elementOrder","parsedMesh","nodesXCoordinates","nodesX","nodesY","calculateSystemSize","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","GenericBoundaryConditions","constructor","boundaryElements","nop","this","imposeConstantValueBoundaryConditions","Object","keys","forEach","boundaryKey","value","elementIndex","side","nodeIndex","globalNodeIndex","colIndex","BasisFunctions","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","maxX","maxY","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","undefined","fixedBoundaryElements","boundaryNodePairs","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","generate1DNodalNumbering","findBoundaryElements","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","assembleFrontPropagationMat","eikonalViscousTerm","mesh","nodesCoordinatesAndNumbering","totalElements","xCoordinates","yCoordinates","ksiDerivX","etaDerivX","ksiDerivY","etaDerivY","detJacobian","solutionDerivX","solutionDerivY","localToGlobalMap","basisFunctionDerivX","basisFunctionDerivY","basisFunctions","gaussPointsAndWeights","numNodes","localNodeIndex","gaussPointIndex1","basisFunctionsAndDerivatives","gaussPointIndex2","localNodeIndex1","localToGlobalMap1","localNodeIndex2","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","FEAScriptModel","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","Error","thermalBoundaryConditions","assembleSolidHeatTransferMat","newtonRaphsonResult","importGmshQuadTri","file","result","gmshV","ascii","fltBytes","lines","text","split","map","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","test","parseInt","slice","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","plotSolution","plotType","plotDivId","meshType","yData","arr","xData","from","lineData","mode","type","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","l","r","t","b","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","val","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","isAllowedOrigin","warn","id","path","argumentList","fromWireValue","returnValue","parent","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","FEAScriptWorker","worker","feaWorker","isReady","_initWorker","Worker","URL","url","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","toFixed","getModelInfo","ping","terminate","VERSION"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"feascript.esm.js","sources":["../src/methods/euclideanNormScript.js","../src/utilities/loggingScript.js","../src/methods/linearSystemSolverScript.js","../src/methods/jacobiSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/mesh/basisFunctionsScript.js","../src/mesh/meshGenerationScript.js","../src/methods/numericalIntegrationScript.js","../src/mesh/meshUtilsScript.js","../src/solvers/genericBoundaryConditionsScript.js","../src/solvers/frontPropagationScript.js","../src/solvers/thermalBoundaryConditionsScript.js","../src/methods/frontalSolverScript.js","../src/solvers/solidHeatTransferScript.js","../src/FEAScript.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.js","../src/vendor/comlink.mjs","../src/workers/workerScript.js","../src/index.js"],"sourcesContent":["// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to calculate the Euclidean norm of a vector\n * @param {array} vector - The input vector\n * @returns {number} The Euclidean norm of the vector\n */\nexport function euclideanNorm(vector) {\n let norm = 0;\n for (let i = 0; i < vector.length; i++) {\n norm += vector[i] * vector[i];\n }\n norm = Math.sqrt(norm);\n return norm;\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Global logging level\nlet currentLogLevel = \"basic\";\n\n/**\n * Function to set the logging system level\n * @param {string} level - Logging level (basic, debug)\n */\nexport function logSystem(level) {\n if (level !== \"basic\" && level !== \"debug\") {\n console.log(\n \"%c[WARN] Invalid log level: \" + level + \". Using basic instead.\",\n \"color: #FFC107; font-weight: bold;\"\n ); // Yellow for warnings\n currentLogLevel = \"basic\";\n } else {\n currentLogLevel = level;\n basicLog(`Log level set to: ${level}`);\n }\n}\n\n/**\n * Function to log debug messages - only logs if level is 'debug'\n * @param {string} message - Message to log\n */\nexport function debugLog(message) {\n if (currentLogLevel === \"debug\") {\n console.log(\"%c[DEBUG] \" + message, \"color: #2196F3; font-weight: bold;\"); // Blue color for debug\n }\n}\n\n/**\n * Function to log basic information - always logs\n * @param {string} message - Message to log\n */\nexport function basicLog(message) {\n console.log(\"%c[INFO] \" + message, \"color: #4CAF50; font-weight: bold;\"); // Green color for basic info\n}\n\n/**\n * Function to log error messages\n * @param {string} message - Message to log\n */\nexport function errorLog(message) {\n console.log(\"%c[ERROR] \" + message, \"color: #F44336; font-weight: bold;\"); // Red color for errors\n}\n\n/**\n * Function to handle version information and fetch the latest update date and release from GitHub\n */\nexport async function printVersion() {\n basicLog(\"Fetching latest FEAScript version information...\");\n try {\n const commitResponse = await fetch(\"https://api.github.com/repos/FEAScript/FEAScript/commits/main\");\n const commitData = await commitResponse.json();\n const latestCommitDate = new Date(commitData.commit.committer.date).toLocaleString();\n basicLog(`Latest FEAScript update: ${latestCommitDate}`);\n return latestCommitDate;\n } catch (error) {\n errorLog(\"Failed to fetch version information: \" + error);\n return \"Version information unavailable\";\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiSolver } from \"./jacobiSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to solve a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (\"lusolve\" or \"jacobi\")\n * @param {Array} jacobianMatrix - The coefficient matrix\n * @param {Array} residualVector - The right-hand side vector\n * @param {object} [options] - Additional options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum iterations for iterative methods\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance for iterative methods\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - converged: Boolean indicating whether the method converged (for iterative methods)\n * - iterations: Number of iterations performed (for iterative methods)\n */\nexport function solveLinearSystem(solverMethod, jacobianMatrix, residualVector, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n\n let solutionVector = [];\n let converged = true;\n let iterations = 0;\n\n // Solve the linear system based on the specified solver method\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n if (solverMethod === \"lusolve\") {\n // Use LU decomposition method\n const jacobianMatrixSparse = math.sparse(jacobianMatrix);\n const luFactorization = math.slu(jacobianMatrixSparse, 1, 1); // order=1, threshold=1 for pivoting\n let solutionMatrix = math.lusolve(luFactorization, residualVector);\n solutionVector = math.squeeze(solutionMatrix).valueOf();\n //solutionVector = math.lusolve(jacobianMatrix, residualVector); // In the case of a dense matrix\n } else if (solverMethod === \"jacobi\") {\n // Use Jacobi method\n const initialGuess = new Array(residualVector.length).fill(0);\n const jacobiSolverResult = jacobiSolver(jacobianMatrix, residualVector, initialGuess, {\n maxIterations,\n tolerance,\n });\n\n // Log convergence information\n if (jacobiSolverResult.converged) {\n debugLog(`Jacobi method converged in ${jacobiSolverResult.iterations} iterations`);\n } else {\n debugLog(`Jacobi method did not converge after ${jacobiSolverResult.iterations} iterations`);\n }\n\n solutionVector = jacobiSolverResult.solutionVector;\n converged = jacobiSolverResult.converged;\n iterations = jacobiSolverResult.iterations;\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n return { solutionVector, converged, iterations };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method\n * @param {array} jacobianMatrix - The coefficient matrix (must be square)\n * @param {array} residualVector - The right-hand side vector\n * @param {array} initialGuess - Initial guess for solution vector\n * @param {object} [options] - Options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum number of iterations\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\nexport function jacobiSolver(jacobianMatrix, residualVector, initialGuess, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n const n = jacobianMatrix.length; // Size of the square matrix\n let x = [...initialGuess]; // Current solution (starts with initial guess)\n let xNew = new Array(n); // Next iteration's solution\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n // Perform one iteration\n for (let i = 0; i < n; i++) {\n let sum = 0;\n // Calculate sum of jacobianMatrix[i][j] * x[j] for j ≠ i\n for (let j = 0; j < n; j++) {\n if (j !== i) {\n sum += jacobianMatrix[i][j] * x[j];\n }\n }\n // Update xNew[i] using the Jacobi formula\n xNew[i] = (residualVector[i] - sum) / jacobianMatrix[i][i];\n }\n\n // Check convergence\n let maxDiff = 0;\n for (let i = 0; i < n; i++) {\n maxDiff = Math.max(maxDiff, Math.abs(xNew[i] - x[i]));\n }\n\n // Update x for next iteration\n x = [...xNew];\n\n // Successfully converged if maxDiff is less than tolerance\n if (maxDiff < tolerance) {\n return {\n solutionVector: x,\n iterations: iteration + 1,\n converged: true,\n };\n }\n }\n\n // maxIterations were reached without convergence\n return {\n solutionVector: x,\n iterations: maxIterations,\n converged: false,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { euclideanNorm } from \"../methods/euclideanNormScript.js\";\nimport { solveLinearSystem } from \"./linearSystemSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to solve a system of non-linear equations using the Newton-Raphson method\n * @param {number} [maxIterations=100] - Maximum number of iterations\n * @param {number} [tolerance=1e-4] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\n\nexport function newtonRaphson(assembleMat, context, maxIterations = 100, tolerance = 1e-4) {\n let errorNorm = 0;\n let converged = false;\n let iterations = 0;\n let deltaX = [];\n let solutionVector = [];\n let jacobianMatrix = [];\n let residualVector = [];\n\n // Calculate system size from meshData instead of meshConfig\n let totalNodes = context.meshData.nodesXCoordinates.length;\n\n // Initialize arrays with proper size\n for (let i = 0; i < totalNodes; i++) {\n deltaX[i] = 0;\n solutionVector[i] = 0;\n }\n\n // Initialize solution from context if available\n if (context.initialSolution && context.initialSolution.length === totalNodes) {\n solutionVector = [...context.initialSolution];\n }\n\n while (iterations < maxIterations && !converged) {\n // Update solution\n for (let i = 0; i < solutionVector.length; i++) {\n solutionVector[i] = Number(solutionVector[i]) + Number(deltaX[i]);\n }\n\n // Compute Jacobian and residual matrices\n ({ jacobianMatrix, residualVector } = assembleMat(\n context.meshData,\n context.boundaryConditions,\n solutionVector, // The solution vector is required in the case of a non-linear equation\n context.eikonalActivationFlag // Currently used only in the front propagation solver (TODO refactor in case of a solver not needing it)\n ));\n\n // Solve the linear system based on the specified solver method\n const linearSystemResult = solveLinearSystem(context.solverMethod, jacobianMatrix, residualVector);\n deltaX = linearSystemResult.solutionVector;\n\n // Check convergence\n errorNorm = euclideanNorm(deltaX);\n\n // Norm for each iteration\n basicLog(`Newton-Raphson iteration ${iterations + 1}: Error norm = ${errorNorm.toExponential(4)}`);\n\n if (errorNorm <= tolerance) {\n converged = true;\n } else if (errorNorm > 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n errorLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n // Validate geometry parameters (when not using a parsed mesh)\n if (\n !parsedMesh &&\n (this.numElementsX === null || this.maxX === null || this.numElementsY === null || this.maxY === null)\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nimport { BasisFunctions } from \"./basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"./meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to prepare the mesh for finite element analysis\n * @param {object} meshConfig - Object containing computational mesh details\n * @returns {object} An object containing all mesh-related data\n */\nexport function prepareMesh(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, maxX, maxY, elementOrder, parsedMesh } = meshConfig;\n\n // Create a new instance of the Mesh class\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nop,\n boundaryElements,\n totalElements,\n totalNodes,\n meshDimension,\n elementOrder,\n };\n}\n\n/**\n * Function to initialize the FEA matrices and numerical tools\n * @param {object} meshData - Object containing mesh data from prepareMesh()\n * @returns {object} An object containing initialized matrices and numerical tools\n */\nexport function initializeFEA(meshData) {\n const { totalNodes, nop, meshDimension, elementOrder } = meshData;\n\n // Initialize variables for matrix assembly\n let residualVector = [];\n let jacobianMatrix = [];\n let localToGlobalMap = [];\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n let gaussPoints = gaussPointsAndWeights.gaussPoints;\n let gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n return {\n residualVector,\n jacobianMatrix,\n localToGlobalMap,\n basisFunctions,\n gaussPoints,\n gaussWeights,\n numNodes,\n };\n}\n\n/**\n * Function to perform isoparametric mapping for 1D elements\n * @param {object} params - Parameters for the mapping\n * @returns {object} An object containing the mapped data\n */\nexport function performIsoparametricMapping1D(params) {\n const { basisFunction, basisFunctionDerivKsi, nodesXCoordinates, localToGlobalMap, numNodes } = params;\n\n let xCoordinates = 0;\n let ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n let detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n let basisFunctionDerivX = [];\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian;\n }\n\n return {\n xCoordinates,\n detJacobian,\n basisFunctionDerivX,\n };\n}\n\n/**\n * Function to perform isoparametric mapping for 2D elements\n * @param {object} params - Parameters for the mapping\n * @returns {object} An object containing the mapped data\n */\nexport function performIsoparametricMapping2D(params) {\n const {\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n } = params;\n\n let xCoordinates = 0;\n let yCoordinates = 0;\n let ksiDerivX = 0;\n let etaDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates += nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY += nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY += nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n let detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n let basisFunctionDerivX = [];\n let basisFunctionDerivY = [];\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n return {\n xCoordinates,\n yCoordinates,\n detJacobian,\n basisFunctionDerivX,\n basisFunctionDerivY,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport {\n initializeFEA,\n performIsoparametricMapping1D,\n performIsoparametricMapping2D,\n} from \"../mesh/meshUtilsScript.js\";\nimport { basicLog, debugLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the Jacobian matrix and residuals vector for the front propagation model\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n */\nexport function assembleFrontPropagationMat(\n meshData,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n // Calculate eikonal viscous term\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh data\n const {\n nodesXCoordinates,\n nodesYCoordinates,\n nop,\n boundaryElements,\n totalElements,\n meshDimension,\n elementOrder,\n } = meshData;\n\n // Initialize FEA components\n const FEAData = initializeFEA(meshData);\n const {\n residualVector,\n jacobianMatrix,\n localToGlobalMap,\n basisFunctions,\n gaussPoints,\n gaussWeights,\n numNodes,\n } = FEAData;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n // Map local element nodes to global mesh nodes\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n // Get basis functions for the current Gauss point\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n\n // Perform isoparametric mapping\n const mappingResult = performIsoparametricMapping1D({\n basisFunction: basisFunctionsAndDerivatives.basisFunction,\n basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Extract mapping results\n const { detJacobian, basisFunctionDerivX } = mappingResult;\n const basisFunction = basisFunctionsAndDerivatives.basisFunction;\n\n // Calculate solution derivative\n let solutionDerivX = 0;\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n }\n // 2D front propagation (eikonal) equation\n else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Get basis functions for the current Gauss point\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n\n // Perform isoparametric mapping\n const mappingResult = performIsoparametricMapping2D({\n basisFunction: basisFunctionsAndDerivatives.basisFunction,\n basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi,\n basisFunctionDerivEta: basisFunctionsAndDerivatives.basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Extract mapping results\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = mappingResult;\n const basisFunction = basisFunctionsAndDerivatives.basisFunction;\n\n // Calculate solution derivatives\n let solutionDerivX = 0;\n let solutionDerivY = 0;\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n\n // residualVector: Viscous term contribution (to stabilize the solution)\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n\n // residualVector: Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n\n // jacobianMatrix: Viscous term contribution\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n\n // jacobianMatrix: Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]\n ) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2];\n }\n }\n }\n }\n }\n }\n }\n\n // Apply boundary conditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals in debug mode\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { assembleSolidHeatTransferFront } from \"../solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// Add an exported wrapper to obtain results for plotting\nexport function runFrontalSolver(meshConfig, boundaryConditions) {\n main(meshConfig, boundaryConditions);\n return {\n solutionVector: block1.u.slice(0, block1.np),\n nodesCoordinates: {\n nodesXCoordinates: block1.xpt.slice(0, block1.np),\n nodesYCoordinates: block1.ypt.slice(0, block1.np),\n },\n };\n}\n\n// Constants\nconst nemax = 1600;\nconst nnmax = 6724;\nconst nmax = 2000;\n\n// Common block equivalents as objects\nconst block1 = {\n nex: 0,\n ney: 0,\n nnx: 0,\n nny: 0,\n ne: 0,\n np: 0,\n xorigin: 0,\n yorigin: 0,\n xlast: 0,\n ylast: 0,\n deltax: 0,\n deltay: 0,\n nop: Array(nemax)\n .fill()\n .map(() => Array(9).fill(0)),\n xpt: Array(nnmax).fill(0),\n ypt: Array(nnmax).fill(0),\n ncod: Array(nnmax).fill(0),\n bc: Array(nnmax).fill(0),\n r1: Array(nnmax).fill(0),\n u: Array(nnmax).fill(0),\n ntop: Array(nemax).fill(0),\n nlat: Array(nemax).fill(0),\n};\n\nconst gauss = {\n w: [0.27777777777778, 0.444444444444, 0.27777777777778],\n gp: [0.1127016654, 0.5, 0.8872983346],\n};\n\nconst fro1 = {\n iwr1: 0,\n npt: 0,\n ntra: 0,\n nbn: Array(nemax).fill(0),\n det: 1,\n sk: Array(nmax * nmax).fill(0),\n ice1: 0,\n};\n\nconst fabf1 = {\n estifm: Array(9)\n .fill()\n .map(() => Array(9).fill(0)),\n nell: 0,\n};\n\nconst fb1 = {\n ecv: Array(2000000).fill(0),\n lhed: Array(nmax).fill(0),\n qq: Array(nmax).fill(0),\n ecpiv: Array(2000000).fill(0),\n};\n\n// Instantiate shared basis functions handler (biquadratic 2D)\nconst basisFunctionsLib = new BasisFunctions({ meshDimension: \"2D\", elementOrder: \"quadratic\" });\n\n// Main program logic\nfunction main(meshConfig, boundaryConditions) {\n // console.log(\"2-D problem. Biquadratic basis functions\\n\");\n\n xydiscr(meshConfig);\n nodnumb();\n xycoord();\n // console.log(`nex=${block1.nex} ney=${block1.ney} ne=${block1.ne} np=${block1.np}\\n`);\n\n // Initialize all nodes with no boundary condition\n for (let i = 0; i < block1.np; i++) {\n block1.ncod[i] = 0;\n block1.bc[i] = 0;\n }\n\n // Apply boundary conditions based on the boundaryConditions parameter\n Object.keys(boundaryConditions).forEach((boundaryKey) => {\n const condition = boundaryConditions[boundaryKey];\n\n // Handle constantTemp (Dirichlet) boundary conditions\n if (condition[0] === \"constantTemp\") {\n const tempValue = boundaryConditions[boundaryKey][1];\n\n // Apply boundary condition to the appropriate nodes based on boundary key\n switch (boundaryKey) {\n case \"0\": // Bottom boundary (y = yorigin)\n for (let col = 0; col < block1.nnx; col++) {\n const nodeIndex = col * block1.nny;\n block1.ncod[nodeIndex] = 1;\n block1.bc[nodeIndex] = tempValue;\n }\n break;\n\n case \"1\": // Right boundary (x = xlast)\n for (let j = 0; j < block1.nny; j++) {\n block1.ncod[j] = 1;\n block1.bc[j] = tempValue;\n }\n break;\n\n case \"2\": // Top boundary (y = ylast)\n for (let col = 0; col < block1.nnx; col++) {\n const nodeIndex = col * block1.nny + (block1.nny - 1);\n block1.ncod[nodeIndex] = 1;\n block1.bc[nodeIndex] = tempValue;\n }\n break;\n\n case \"3\": // Left boundary (x = xorigin)\n for (let j = 0; j < block1.nny; j++) {\n const nodeIndex = (block1.nnx - 1) * block1.nny + j;\n block1.ncod[nodeIndex] = 1;\n block1.bc[nodeIndex] = tempValue;\n }\n break;\n }\n }\n // Other boundary condition types can be handled later if needed\n });\n\n // Prepare natural boundary conditions\n for (let i = 0; i < block1.ne; i++) {\n block1.ntop[i] = 0;\n block1.nlat[i] = 0;\n }\n\n // for (let i = block1.ney - 1; i < block1.ne; i += block1.ney) {\n // block1.ntop[i] = 1;\n // }\n\n // for (let i = block1.ne - block1.ney; i < block1.ne; i++) {\n // block1.nlat[i] = 1;\n // }\n\n // Initialization\n for (let i = 0; i < block1.np; i++) {\n block1.r1[i] = 0;\n }\n\n fro1.npt = block1.np;\n fro1.iwr1 = 0;\n fro1.ntra = 1;\n fro1.det = 1;\n\n for (let i = 0; i < block1.ne; i++) {\n fro1.nbn[i] = 9;\n }\n\n front();\n\n // Copy solution\n for (let i = 0; i < block1.np; i++) {\n block1.u[i] = fro1.sk[i];\n }\n\n // Output results to console\n for (let i = 0; i < block1.np; i++) {\n debugLog(\n `${block1.xpt[i].toExponential(5)} ${block1.ypt[i].toExponential(5)} ${block1.u[i].toExponential(5)}`\n );\n }\n}\n\n// Discretization\nfunction xydiscr(meshConfig) {\n // Extract values from meshConfig\n const { meshDimension, numElementsX, numElementsY, maxX, maxY, elementOrder, parsedMesh } = meshConfig;\n\n block1.nex = numElementsX;\n block1.ney = numElementsY;\n block1.xorigin = 0;\n block1.yorigin = 0;\n block1.xlast = maxX;\n block1.ylast = maxY;\n block1.deltax = (block1.xlast - block1.xorigin) / block1.nex;\n block1.deltay = (block1.ylast - block1.yorigin) / block1.ney;\n}\n\n// Nodal numbering\nfunction nodnumb() {\n block1.ne = block1.nex * block1.ney;\n block1.nnx = 2 * block1.nex + 1;\n block1.nny = 2 * block1.ney + 1;\n block1.np = block1.nnx * block1.nny;\n\n let nel = 0;\n for (let i = 1; i <= block1.nex; i++) {\n for (let j = 1; j <= block1.ney; j++) {\n nel++;\n for (let k = 1; k <= 3; k++) {\n let l = 3 * k - 2;\n block1.nop[nel - 1][l - 1] = block1.nny * (2 * i + k - 3) + 2 * j - 1;\n block1.nop[nel - 1][l] = block1.nop[nel - 1][l - 1] + 1;\n block1.nop[nel - 1][l + 1] = block1.nop[nel - 1][l - 1] + 2;\n }\n }\n }\n}\n\n// Coordinate setup\nfunction xycoord() {\n block1.xpt[0] = block1.xorigin;\n block1.ypt[0] = block1.yorigin;\n\n for (let i = 1; i <= block1.nnx; i++) {\n let nnode = (i - 1) * block1.nny;\n block1.xpt[nnode] = block1.xpt[0] + ((i - 1) * block1.deltax) / 2;\n block1.ypt[nnode] = block1.ypt[0];\n\n for (let j = 2; j <= block1.nny; j++) {\n block1.xpt[nnode + j - 1] = block1.xpt[nnode];\n block1.ypt[nnode + j - 1] = block1.ypt[nnode] + ((j - 1) * block1.deltay) / 2;\n }\n }\n}\n\n// Element stiffness matrix and residuals (delegated to external assembly function)\nfunction abfind() {\n const elementIndex = fabf1.nell - 1;\n\n const { estifm, localLoad, ngl } = assembleSolidHeatTransferFront({\n elementIndex,\n nop: block1.nop,\n xCoordinates: block1.xpt,\n yCoordinates: block1.ypt,\n basisFunctions: basisFunctionsLib,\n gaussPoints: gauss.gp,\n gaussWeights: gauss.w,\n ntopFlag: block1.ntop[elementIndex] === 1,\n nlatFlag: block1.nlat[elementIndex] === 1,\n });\n\n // Copy element matrix\n for (let i = 0; i < 9; i++) {\n for (let j = 0; j < 9; j++) {\n fabf1.estifm[i][j] = estifm[i][j];\n }\n }\n\n // Accumulate local load into global RHS\n for (let a = 0; a < 9; a++) {\n const g = ngl[a] - 1;\n block1.r1[g] += localLoad[a];\n }\n}\n\n// Frontal solver\nfunction front() {\n let ldest = Array(9).fill(0);\n let kdest = Array(9).fill(0);\n let khed = Array(nmax).fill(0);\n let kpiv = Array(nmax).fill(0);\n let lpiv = Array(nmax).fill(0);\n let jmod = Array(nmax).fill(0);\n let pvkol = Array(nmax).fill(0);\n let eq = Array(nmax)\n .fill()\n .map(() => Array(nmax).fill(0));\n let nrs = Array(nnmax).fill(0);\n let ncs = Array(nnmax).fill(0);\n let check = Array(nnmax).fill(0);\n let lco; // Declare lco once at function scope\n\n let ice = 1;\n fro1.iwr1++;\n let ipiv = 1;\n let nsum = 1;\n fabf1.nell = 0;\n\n for (let i = 0; i < fro1.npt; i++) {\n nrs[i] = 0;\n ncs[i] = 0;\n }\n\n if (fro1.ntra !== 0) {\n // Prefront: find last appearance of each node\n for (let i = 0; i < fro1.npt; i++) {\n check[i] = 0;\n }\n\n for (let i = 0; i < block1.ne; i++) {\n let nep = block1.ne - i - 1;\n for (let j = 0; j < fro1.nbn[nep]; j++) {\n let k = block1.nop[nep][j];\n if (check[k - 1] === 0) {\n check[k - 1] = 1;\n block1.nop[nep][j] = -block1.nop[nep][j];\n }\n }\n }\n }\n\n fro1.ntra = 0;\n let lcol = 0;\n let krow = 0;\n\n for (let i = 0; i < nmax; i++) {\n for (let j = 0; j < nmax; j++) {\n eq[j][i] = 0;\n }\n }\n\n while (true) {\n fabf1.nell++;\n abfind();\n\n let n = fabf1.nell;\n let nend = fro1.nbn[n - 1];\n let lend = fro1.nbn[n - 1];\n\n for (let lk = 0; lk < lend; lk++) {\n let nodk = block1.nop[n - 1][lk];\n let ll;\n\n if (lcol === 0) {\n lcol++;\n ldest[lk] = lcol;\n fb1.lhed[lcol - 1] = nodk;\n } else {\n for (ll = 0; ll < lcol; ll++) {\n if (Math.abs(nodk) === Math.abs(fb1.lhed[ll])) break;\n }\n\n if (ll === lcol) {\n lcol++;\n ldest[lk] = lcol;\n fb1.lhed[lcol - 1] = nodk;\n } else {\n ldest[lk] = ll + 1;\n fb1.lhed[ll] = nodk;\n }\n }\n\n let kk;\n if (krow === 0) {\n krow++;\n kdest[lk] = krow;\n khed[krow - 1] = nodk;\n } else {\n for (kk = 0; kk < krow; kk++) {\n if (Math.abs(nodk) === Math.abs(khed[kk])) break;\n }\n\n if (kk === krow) {\n krow++;\n kdest[lk] = krow;\n khed[krow - 1] = nodk;\n } else {\n kdest[lk] = kk + 1;\n khed[kk] = nodk;\n }\n }\n }\n\n if (krow > nmax || lcol > nmax) {\n errorLog(\"Error: nmax-nsum not large enough\");\n return;\n }\n\n for (let l = 0; l < lend; l++) {\n let ll = ldest[l];\n for (let k = 0; k < nend; k++) {\n let kk = kdest[k];\n eq[kk - 1][ll - 1] += fabf1.estifm[k][l];\n }\n }\n\n let lc = 0;\n for (let l = 0; l < lcol; l++) {\n if (fb1.lhed[l] < 0) {\n lpiv[lc] = l + 1;\n lc++;\n }\n }\n\n let ir = 0;\n let kr = 0;\n for (let k = 0; k < krow; k++) {\n let kt = khed[k];\n if (kt < 0) {\n kpiv[kr] = k + 1;\n kr++;\n let kro = Math.abs(kt);\n if (block1.ncod[kro - 1] === 1) {\n jmod[ir] = k + 1;\n ir++;\n block1.ncod[kro - 1] = 2;\n block1.r1[kro - 1] = block1.bc[kro - 1];\n }\n }\n }\n\n if (ir > 0) {\n for (let irr = 0; irr < ir; irr++) {\n let k = jmod[irr] - 1;\n let kh = Math.abs(khed[k]);\n for (let l = 0; l < lcol; l++) {\n eq[k][l] = 0;\n let lh = Math.abs(fb1.lhed[l]);\n if (lh === kh) eq[k][l] = 1;\n }\n }\n }\n\n if (lc > nsum || fabf1.nell < block1.ne) {\n if (lc === 0) {\n errorLog(\"Error: no more rows fully summed\");\n return;\n }\n\n let kpivro = kpiv[0];\n let lpivco = lpiv[0];\n let pivot = eq[kpivro - 1][lpivco - 1];\n\n if (Math.abs(pivot) < 1e-4) {\n pivot = 0;\n for (let l = 0; l < lc; l++) {\n let lpivc = lpiv[l];\n for (let k = 0; k < kr; k++) {\n let kpivr = kpiv[k];\n let piva = eq[kpivr - 1][lpivc - 1];\n if (Math.abs(piva) > Math.abs(pivot)) {\n pivot = piva;\n lpivco = lpivc;\n kpivro = kpivr;\n }\n }\n }\n }\n\n let kro = Math.abs(khed[kpivro - 1]);\n lco = Math.abs(fb1.lhed[lpivco - 1]); // Assign, don't declare\n let nhlp = kro + lco + nrs[kro - 1] + ncs[lco - 1];\n fro1.det = (fro1.det * pivot * (-1) ** nhlp) / Math.abs(pivot);\n\n for (let iperm = 0; iperm < fro1.npt; iperm++) {\n if (iperm >= kro) nrs[iperm]--;\n if (iperm >= lco) ncs[iperm]--;\n }\n\n if (Math.abs(pivot) < 1e-10) {\n errorLog(\n `Warning: matrix singular or ill-conditioned, nell=${fabf1.nell}, kro=${kro}, lco=${lco}, pivot=${pivot}`\n );\n }\n\n if (pivot === 0) return;\n\n for (let l = 0; l < lcol; l++) {\n fb1.qq[l] = eq[kpivro - 1][l] / pivot;\n }\n\n let rhs = block1.r1[kro - 1] / pivot;\n block1.r1[kro - 1] = rhs;\n pvkol[kpivro - 1] = pivot;\n\n if (kpivro > 1) {\n for (let k = 0; k < kpivro - 1; k++) {\n let krw = Math.abs(khed[k]);\n let fac = eq[k][lpivco - 1];\n pvkol[k] = fac;\n if (lpivco > 1 && fac !== 0) {\n for (let l = 0; l < lpivco - 1; l++) {\n eq[k][l] -= fac * fb1.qq[l];\n }\n }\n if (lpivco < lcol) {\n for (let l = lpivco; l < lcol; l++) {\n eq[k][l - 1] = eq[k][l] - fac * fb1.qq[l];\n }\n }\n block1.r1[krw - 1] -= fac * rhs;\n }\n }\n\n if (kpivro < krow) {\n for (let k = kpivro; k < krow; k++) {\n let krw = Math.abs(khed[k]);\n let fac = eq[k][lpivco - 1];\n pvkol[k] = fac;\n if (lpivco > 1) {\n for (let l = 0; l < lpivco - 1; l++) {\n eq[k - 1][l] = eq[k][l] - fac * fb1.qq[l];\n }\n }\n if (lpivco < lcol) {\n for (let l = lpivco; l < lcol; l++) {\n eq[k - 1][l - 1] = eq[k][l] - fac * fb1.qq[l];\n }\n }\n block1.r1[krw - 1] -= fac * rhs;\n }\n }\n\n for (let i = 0; i < krow; i++) {\n fb1.ecpiv[ipiv + i - 1] = pvkol[i];\n }\n ipiv += krow;\n\n for (let i = 0; i < krow; i++) {\n fb1.ecpiv[ipiv + i - 1] = khed[i];\n }\n ipiv += krow;\n\n fb1.ecpiv[ipiv - 1] = kpivro;\n ipiv++;\n\n for (let i = 0; i < lcol; i++) {\n fb1.ecv[ice - 1 + i] = fb1.qq[i];\n }\n ice += lcol;\n\n for (let i = 0; i < lcol; i++) {\n fb1.ecv[ice - 1 + i] = fb1.lhed[i];\n }\n ice += lcol;\n\n fb1.ecv[ice - 1] = kro;\n fb1.ecv[ice] = lcol;\n fb1.ecv[ice + 1] = lpivco;\n fb1.ecv[ice + 2] = pivot;\n ice += 4;\n\n for (let k = 0; k < krow; k++) {\n eq[k][lcol - 1] = 0;\n }\n\n for (let l = 0; l < lcol; l++) {\n eq[krow - 1][l] = 0;\n }\n\n lcol--;\n if (lpivco < lcol + 1) {\n for (let l = lpivco - 1; l < lcol; l++) {\n fb1.lhed[l] = fb1.lhed[l + 1];\n }\n }\n\n krow--;\n if (kpivro < krow + 1) {\n for (let k = kpivro - 1; k < krow; k++) {\n khed[k] = khed[k + 1];\n }\n }\n\n if (krow > 1 || fabf1.nell < block1.ne) continue;\n\n lco = Math.abs(fb1.lhed[0]); // Assign, don't declare\n kpivro = 1;\n pivot = eq[0][0];\n kro = Math.abs(khed[0]);\n lpivco = 1;\n nhlp = kro + lco + nrs[kro - 1] + ncs[lco - 1];\n fro1.det = (fro1.det * pivot * (-1) ** nhlp) / Math.abs(pivot);\n\n fb1.qq[0] = 1;\n if (Math.abs(pivot) < 1e-10) {\n errorLog(\n `Warning: matrix singular or ill-conditioned, nell=${fabf1.nell}, kro=${kro}, lco=${lco}, pivot=${pivot}`\n );\n }\n\n if (pivot === 0) return;\n\n block1.r1[kro - 1] = block1.r1[kro - 1] / pivot;\n fb1.ecv[ice - 1] = fb1.qq[0];\n ice++;\n fb1.ecv[ice - 1] = fb1.lhed[0];\n ice++;\n fb1.ecv[ice - 1] = kro;\n fb1.ecv[ice] = lcol;\n fb1.ecv[ice + 1] = lpivco;\n fb1.ecv[ice + 2] = pivot;\n ice += 4;\n\n fb1.ecpiv[ipiv - 1] = pvkol[0];\n ipiv++;\n fb1.ecpiv[ipiv - 1] = khed[0];\n ipiv++;\n fb1.ecpiv[ipiv - 1] = kpivro;\n ipiv++;\n\n fro1.ice1 = ice;\n if (fro1.iwr1 === 1) debugLog(`total ecs transfer in matrix reduction=${ice}`);\n\n bacsub(ice);\n break;\n }\n }\n}\n\n// Back substitution\nfunction bacsub(ice) {\n for (let i = 0; i < fro1.npt; i++) {\n fro1.sk[i] = block1.bc[i];\n }\n\n for (let iv = 1; iv <= fro1.npt; iv++) {\n ice -= 4;\n let kro = fb1.ecv[ice - 1];\n let lcol = fb1.ecv[ice];\n let lpivco = fb1.ecv[ice + 1];\n let pivot = fb1.ecv[ice + 2];\n\n if (iv === 1) {\n ice--;\n fb1.lhed[0] = fb1.ecv[ice - 1];\n ice--;\n fb1.qq[0] = fb1.ecv[ice - 1];\n } else {\n ice -= lcol;\n for (let iii = 0; iii < lcol; iii++) {\n fb1.lhed[iii] = fb1.ecv[ice - 1 + iii];\n }\n ice -= lcol;\n for (let iii = 0; iii < lcol; iii++) {\n fb1.qq[iii] = fb1.ecv[ice - 1 + iii];\n }\n }\n\n let lco = Math.abs(fb1.lhed[lpivco - 1]);\n if (block1.ncod[lco - 1] > 0) continue;\n\n let gash = 0;\n fb1.qq[lpivco - 1] = 0;\n for (let l = 0; l < lcol; l++) {\n gash -= fb1.qq[l] * fro1.sk[Math.abs(fb1.lhed[l]) - 1];\n }\n\n fro1.sk[lco - 1] = gash + block1.r1[kro - 1];\n\n block1.ncod[lco - 1] = 1;\n }\n\n if (fro1.iwr1 === 1) debugLog(`value of ice after backsubstitution=${ice}`);\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport {\n initializeFEA,\n performIsoparametricMapping1D,\n performIsoparametricMapping2D,\n} from \"../mesh/meshUtilsScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the Jacobian matrix and residuals vector for the solid heat transfer model\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n */\nexport function assembleSolidHeatTransferMat(meshData, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh data\n const {\n nodesXCoordinates,\n nodesYCoordinates,\n nop,\n boundaryElements,\n totalElements,\n meshDimension,\n elementOrder,\n } = meshData;\n\n // Initialize FEA components\n const FEAData = initializeFEA(meshData);\n const {\n residualVector,\n jacobianMatrix,\n localToGlobalMap,\n basisFunctions,\n gaussPoints,\n gaussWeights,\n numNodes,\n } = FEAData;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n // Map local element nodes to global mesh nodes\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n // Get basis functions for the current Gauss point\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n\n // Perform isoparametric mapping\n const mappingResult = performIsoparametricMapping1D({\n basisFunction: basisFunctionsAndDerivatives.basisFunction,\n basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Extract mapping results\n const { detJacobian, basisFunctionDerivX } = mappingResult;\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n }\n // 2D solid heat transfer\n else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Get basis functions for the current Gauss point\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n\n // Perform isoparametric mapping\n const mappingResult = performIsoparametricMapping2D({\n basisFunction: basisFunctionsAndDerivatives.basisFunction,\n basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi,\n basisFunctionDerivEta: basisFunctionsAndDerivatives.basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Extract mapping results\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = mappingResult;\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Apply boundary conditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n // Print all residuals in debug mode\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n\n/**\n * Function to assemble the local Jacobian matrix and residuals vector for the solid heat transfer model when using the frontal system solver\n */\nexport function assembleSolidHeatTransferFront({\n elementIndex,\n nop,\n xCoordinates,\n yCoordinates,\n basisFunctions,\n gaussPoints,\n gaussWeights,\n ntopFlag = false,\n nlatFlag = false,\n convectionTop = { active: false, coeff: 0, extTemp: 0 }, // NEW\n}) {\n const numNodes = 9; // biquadratic 2D\n const estifm = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localLoad = Array(numNodes).fill(0);\n\n // Global node numbers (1-based in nop)\n const ngl = Array(numNodes);\n for (let i = 0; i < numNodes; i++) ngl[i] = Math.abs(nop[elementIndex][i]);\n\n // Volume (conductive) contribution\n for (let j = 0; j < gaussPoints.length; j++) {\n for (let k = 0; k < gaussPoints.length; k++) {\n const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } =\n basisFunctions.getBasisFunctions(gaussPoints[j], gaussPoints[k]);\n\n const localToGlobalMap = ngl.map((g) => g - 1);\n\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates: xCoordinates,\n nodesYCoordinates: yCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n for (let a = 0; a < numNodes; a++) {\n for (let b = 0; b < numNodes; b++) {\n estifm[a][b] -=\n gaussWeights[j] *\n gaussWeights[k] *\n detJacobian *\n (basisFunctionDerivX[a] * basisFunctionDerivX[b] +\n basisFunctionDerivY[a] * basisFunctionDerivY[b]);\n }\n }\n }\n }\n\n // Legacy natural boundary terms (top edge eta=1; right edge ksi=1) kept as in original frontal version\n // Replace previous generic top-edge load term with explicit Robin (convection) if requested\n if (ntopFlag && convectionTop.active) {\n const h = convectionTop.coeff;\n const Text = convectionTop.extTemp;\n // Integrate along top edge (eta = 1); local top edge nodes: 2,5,8\n for (let gp = 0; gp < gaussPoints.length; gp++) {\n const ksi = gaussPoints[gp];\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(ksi, 1);\n\n // Compute metric (edge length differential) |dx/dksi|\n let dx_dksi = 0, dy_dksi = 0;\n const topEdgeLocalNodes = [2, 5, 8];\n for (let n = 0; n < 9; n++) {\n const g = nop[elementIndex][n] - 1;\n dx_dksi += xCoordinates[g] * basisFunctionDerivKsi[n];\n dy_dksi += yCoordinates[g] * basisFunctionDerivKsi[n];\n }\n const ds_dksi = Math.sqrt(dx_dksi * dx_dksi + dy_dksi * dy_dksi);\n\n // Assemble Robin contributions\n for (const a of topEdgeLocalNodes) {\n for (const b of topEdgeLocalNodes) {\n estifm[a][b] -= gaussWeights[gp] * ds_dksi * h * basisFunction[a] * basisFunction[b];\n }\n localLoad[a] -= gaussWeights[gp] * ds_dksi * h * Text * basisFunction[a];\n }\n }\n } else if (ntopFlag && !convectionTop.active) {\n // If a zero-flux (symmetry) condition were applied on top, do nothing (natural BC)\n // (Previous placeholder load term removed to avoid unintended flux)\n }\n\n // If needed, similar patterned handling could be added for right edge (nlatFlag) later.\n\n return { estifm, localLoad, ngl };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { prepareMesh } from \"./mesh/meshUtilsScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { runFrontalSolver } from \"./methods/frontalSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n\n // Prepare the mesh\n basicLog(\"Preparing mesh...\");\n const meshData = prepareMesh(this.meshConfig);\n basicLog(\"Mesh preparation completed\");\n\n // Extract node coordinates from meshData\n const nodesCoordinates = {\n nodesXCoordinates: meshData.nodesXCoordinates,\n nodesYCoordinates: meshData.nodesYCoordinates,\n };\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Check if using frontal solver\n if (this.solverMethod === \"frontal\") {\n basicLog(`Using frontal solver method`);\n // Call frontal solver\n const frontalResult = runFrontalSolver(this.meshConfig, this.boundaryConditions);\n solutionVector = frontalResult.solutionVector;\n } else {\n // Use regular linear solver methods\n ({ jacobianMatrix, residualVector } = assembleSolidHeatTransferMat(\n meshData,\n this.boundaryConditions\n ));\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n }\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n const eikonalExteralIterations = 5; // Number of incremental steps for the eikonal equation\n\n // Create context object with all necessary properties\n const context = {\n meshData: meshData,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n // Solve the assembled non-linear system\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n solutionVector = newtonRaphsonResult.solutionVector;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.3\";"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","logSystem","level","console","log","basicLog","debugLog","message","errorLog","async","printVersion","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString","error","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","jacobianMatrixSparse","math","sparse","luFactorization","slu","solutionMatrix","lusolve","squeeze","valueOf","jacobiSolverResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiSolver","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","totalNodes","meshData","nodesXCoordinates","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","BasisFunctions","constructor","meshDimension","elementOrder","this","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","numElementsX","maxX","numElementsY","maxY","parsedMesh","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","boundaryElements","undefined","fixedBoundaryElements","boundaryNodePairs","forEach","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","side","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","nodeIndex","generate1DNodalNumbering","findBoundaryElements","nop","elementIndex","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","initializeFEA","colIndex","basisFunctions","gaussPointsAndWeights","localToGlobalMap","numNodes","performIsoparametricMapping1D","params","xCoordinates","ksiDerivX","localNodeIndex","detJacobian","basisFunctionDerivX","performIsoparametricMapping2D","yCoordinates","etaDerivX","ksiDerivY","etaDerivY","basisFunctionDerivY","GenericBoundaryConditions","imposeConstantValueBoundaryConditions","Object","keys","boundaryKey","value","globalNodeIndex","assembleFrontPropagationMat","eikonalViscousTerm","totalElements","FEAData","gaussPointIndex1","basisFunctionsAndDerivatives","mappingResult","solutionDerivX","localNodeIndex1","localNodeIndex2","gaussPointIndex2","solutionDerivY","localToGlobalMap1","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","runFrontalSolver","meshConfig","block1","nex","ney","xorigin","yorigin","xlast","ylast","deltax","deltay","xydiscr","ne","nnx","nny","np","nel","k","l","nodnumb","xpt","ypt","xycoord","ncod","bc","col","ntop","nlat","r1","fro1","npt","iwr1","ntra","det","nbn","lco","ldest","kdest","khed","nmax","kpiv","lpiv","jmod","pvkol","eq","map","nrs","nnmax","ncs","check","ice","ipiv","nsum","fabf1","nell","nep","lcol","krow","abfind","nend","lend","lk","ll","kk","nodk","fb1","lhed","estifm","lc","ir","kr","kt","kro","irr","kh","kpivro","lpivco","pivot","lpivc","kpivr","piva","nhlp","iperm","qq","rhs","krw","fac","ecpiv","ecv","ice1","bacsub","front","u","sk","main","slice","nodesCoordinates","nemax","gauss","w","gp","basisFunctionsLib","localLoad","ngl","ntopFlag","nlatFlag","convectionTop","active","coeff","g","a","b","h","Text","dx_dksi","dy_dksi","topEdgeLocalNodes","ds_dksi","assembleSolidHeatTransferFront","iv","iii","gash","FEAScriptModel","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","Error","mesh","nodesCoordinatesAndNumbering","prepareMesh","thermalBoundaryConditions","assembleSolidHeatTransferMat","eikonalExteralIterations","newtonRaphsonResult","importGmshQuadTri","file","result","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","test","parseInt","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","plotSolution","plotType","plotDivId","meshType","yData","arr","xData","from","lineData","mode","type","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","r","t","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","val","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","isAllowedOrigin","warn","id","path","argumentList","fromWireValue","returnValue","parent","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","FEAScriptWorker","worker","feaWorker","isReady","_initWorker","Worker","URL","url","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","toFixed","getModelInfo","ping","terminate","VERSION"],"mappings":"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"} \ No newline at end of file diff --git a/dist/feascript.umd.js b/dist/feascript.umd.js index 3af0cfe..35de406 100644 --- a/dist/feascript.umd.js +++ b/dist/feascript.umd.js @@ -1,8 +1,8 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).FEAScript={})}(this,(function(e){"use strict";function t(e){let t=0;for(let n=0;n100){i(`Solution not converged. Error norm: ${l}`);break}m++}return{solutionVector:u,converged:d,iterations:m,jacobianMatrix:c,residualVector:f,nodesCoordinates:p}}class l{constructor(e,t,n,o,s){this.boundaryConditions=e,this.boundaryElements=t,this.nop=n,this.meshDimension=o,this.elementOrder=s}imposeConstantValueBoundaryConditions(e,t){s("Applying constant value boundary conditions (Dirichlet type)"),"1D"===this.meshDimension?Object.keys(this.boundaryConditions).forEach((n=>{if("constantValue"===this.boundaryConditions[n][0]){const s=this.boundaryConditions[n][1];o(`Boundary ${n}: Applying constant value of ${s} (Dirichlet condition)`),this.boundaryElements[n].forEach((([n,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[n][i]-1;o(` - Applied constant value to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[n][i]-1;o(` - Applied constant value to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantValue"===this.boundaryConditions[n][0]){const s=this.boundaryConditions[n][1];o(`Boundary ${n}: Applying constant value of ${s} (Dirichlet condition)`),this.boundaryElements[n].forEach((([n,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[n][i]-1;o(` - Applied constant value to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[n][i]-1;o(` - Applied constant value to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n0&&void 0===this.parsedMesh.boundaryElements[0]){const e=[];for(let t=1;t{if(1===e.dimension){const t=this.parsedMesh.boundaryNodePairs[e.tag]||[];t.length>0&&(this.parsedMesh.boundaryElements[e.tag]||(this.parsedMesh.boundaryElements[e.tag]=[]),t.forEach((t=>{const n=t[0],s=t[1];o(`Processing boundary node pair: [${n}, ${s}] for boundary ${e.tag} (${e.name||"unnamed"})`);let r=!1;for(let t=0;t0&&void 0===this.parsedMesh.boundaryElements[0])){const e=[];for(let t=1;t{if("constantTemp"===this.boundaryConditions[n][0]){const s=this.boundaryConditions[n][1];o(`Boundary ${n}: Applying constant temperature of ${s} K (Dirichlet condition)`),this.boundaryElements[n].forEach((([n,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[n][i]-1;o(` - Applied constant temperature to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[n][i]-1;o(` - Applied constant temperature to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantTemp"===this.boundaryConditions[n][0]){const s=this.boundaryConditions[n][1];o(`Boundary ${n}: Applying constant temperature of ${s} K (Dirichlet condition)`),this.boundaryElements[n].forEach((([n,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[n][i]-1;o(` - Applied constant temperature to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[n][i]-1;o(` - Applied constant temperature to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const t=this.boundaryConditions[e];"convection"===t[0]&&(d[e]=t[1],m[e]=t[2])})),"1D"===this.meshDimension?Object.keys(this.boundaryConditions).forEach((n=>{if("convection"===this.boundaryConditions[n][0]){const s=d[n],i=m[n];o(`Boundary ${n}: Applying convection with heat transfer coefficient h=${s} W/(m²·K) and external temperature T∞=${i} K`),this.boundaryElements[n].forEach((([n,r])=>{let a;"linear"===this.elementOrder?a=0===r?0:1:"quadratic"===this.elementOrder&&(a=0===r?0:2);const l=this.nop[n][a]-1;o(` - Applied convection boundary condition to node ${l+1} (element ${n+1}, local node ${a+1})`),e[l]+=-s*i,t[l][l]+=s}))}})):"2D"===this.meshDimension&&Object.keys(this.boundaryConditions).forEach((s=>{if("convection"===this.boundaryConditions[s][0]){const h=d[s],u=m[s];o(`Boundary ${s}: Applying convection with heat transfer coefficient h=${h} W/(m²·K) and external temperature T∞=${u} K`),this.boundaryElements[s].forEach((([s,d])=>{if("linear"===this.elementOrder){let m,c,f,p,g;0===d?(m=n[0],c=0,f=0,p=3,g=2):1===d?(m=0,c=n[0],f=0,p=2,g=1):2===d?(m=n[0],c=1,f=1,p=4,g=2):3===d&&(m=1,c=n[0],f=2,p=4,g=1);let y=l.getBasisFunctions(m,c),b=y.basisFunction,E=y.basisFunctionDerivKsi,$=y.basisFunctionDerivEta,M=0,v=0,C=0,w=0;const S=this.nop[s].length;for(let e=0;e100){i(`Solution not converged. Error norm: ${l}`);break}c++}return{solutionVector:h,converged:d,iterations:c,jacobianMatrix:m,residualVector:f}}class l{constructor({meshDimension:e,elementOrder:t}){this.meshDimension=e,this.elementOrder=t}getBasisFunctions(e,t=null){let n=[],o=[],s=[];if("1D"===this.meshDimension)"linear"===this.elementOrder?(n[0]=1-e,n[1]=e,o[0]=-1,o[1]=1):"quadratic"===this.elementOrder&&(n[0]=1-3*e+2*e**2,n[1]=4*e-4*e**2,n[2]=2*e**2-e,o[0]=4*e-3,o[1]=4-8*e,o[2]=4*e-1);else if("2D"===this.meshDimension){if(null===t)return void i("Eta coordinate is required for 2D elements");if("linear"===this.elementOrder){function r(e){return 1-e}n[0]=r(e)*r(t),n[1]=r(e)*t,n[2]=e*r(t),n[3]=e*t,o[0]=-1*r(t),o[1]=-1*t,o[2]=1*r(t),o[3]=1*t,s[0]=-1*r(e),s[1]=1*r(e),s[2]=-1*e,s[3]=1*e}else if("quadratic"===this.elementOrder){function a(e){return 2*e**2-3*e+1}function l(e){return-4*e**2+4*e}function d(e){return 2*e**2-e}function c(e){return 4*e-3}function u(e){return-8*e+4}function h(e){return 4*e-1}n[0]=a(e)*a(t),n[1]=a(e)*l(t),n[2]=a(e)*d(t),n[3]=l(e)*a(t),n[4]=l(e)*l(t),n[5]=l(e)*d(t),n[6]=d(e)*a(t),n[7]=d(e)*l(t),n[8]=d(e)*d(t),o[0]=c(e)*a(t),o[1]=c(e)*l(t),o[2]=c(e)*d(t),o[3]=u(e)*a(t),o[4]=u(e)*l(t),o[5]=u(e)*d(t),o[6]=h(e)*a(t),o[7]=h(e)*l(t),o[8]=h(e)*d(t),s[0]=a(e)*c(t),s[1]=a(e)*u(t),s[2]=a(e)*h(t),s[3]=l(e)*c(t),s[4]=l(e)*u(t),s[5]=l(e)*h(t),s[6]=d(e)*c(t),s[7]=d(e)*u(t),s[8]=d(e)*h(t)}}return{basisFunction:n,basisFunctionDerivKsi:o,basisFunctionDerivEta:s}}}class d{constructor({numElementsX:e=null,maxX:t=null,numElementsY:n=null,maxY:o=null,meshDimension:i=null,elementOrder:r="linear",parsedMesh:a=null}){this.numElementsX=e,this.numElementsY=n,this.maxX=t,this.maxY=o,this.meshDimension=i,this.elementOrder=r,this.parsedMesh=a,this.boundaryElementsProcessed=!1,this.parsedMesh&&(s("Using pre-parsed mesh from gmshReader data for mesh generation."),this.parseMeshFromGmsh())}parseMeshFromGmsh(){if(this.parsedMesh.nodalNumbering||i("No valid nodal numbering found in the parsed mesh."),"object"==typeof this.parsedMesh.nodalNumbering&&!Array.isArray(this.parsedMesh.nodalNumbering)){const e=this.parsedMesh.nodalNumbering.quadElements||[];if(this.parsedMesh.nodalNumbering.triangleElements,o("Initial parsed mesh nodal numbering from GMSH format: "+JSON.stringify(this.parsedMesh.nodalNumbering)),this.parsedMesh.elementTypes[3]||this.parsedMesh.elementTypes[10]){const t=[];for(let n=0;n0&&void 0===this.parsedMesh.boundaryElements[0]){const e=[];for(let t=1;t{if(1===e.dimension){const t=this.parsedMesh.boundaryNodePairs[e.tag]||[];t.length>0&&(this.parsedMesh.boundaryElements[e.tag]||(this.parsedMesh.boundaryElements[e.tag]=[]),t.forEach((t=>{const n=t[0],s=t[1];o(`Processing boundary node pair: [${n}, ${s}] for boundary ${e.tag} (${e.name||"unnamed"})`);let r=!1;for(let t=0;t0&&void 0===this.parsedMesh.boundaryElements[0])){const e=[];for(let t=1;t{if("constantValue"===this.boundaryConditions[n][0]){const s=this.boundaryConditions[n][1];o(`Boundary ${n}: Applying constant value of ${s} (Dirichlet condition)`),this.boundaryElements[n].forEach((([n,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[n][i]-1;o(` - Applied constant value to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[n][i]-1;o(` - Applied constant value to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantValue"===this.boundaryConditions[n][0]){const s=this.boundaryConditions[n][1];o(`Boundary ${n}: Applying constant value of ${s} (Dirichlet condition)`),this.boundaryElements[n].forEach((([n,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[n][i]-1;o(` - Applied constant value to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[n][i]-1;o(` - Applied constant value to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantTemp"===this.boundaryConditions[n][0]){const s=this.boundaryConditions[n][1];o(`Boundary ${n}: Applying constant temperature of ${s} K (Dirichlet condition)`),this.boundaryElements[n].forEach((([n,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[n][i]-1;o(` - Applied constant temperature to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[n][i]-1;o(` - Applied constant temperature to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantTemp"===this.boundaryConditions[n][0]){const s=this.boundaryConditions[n][1];o(`Boundary ${n}: Applying constant temperature of ${s} K (Dirichlet condition)`),this.boundaryElements[n].forEach((([n,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[n][i]-1;o(` - Applied constant temperature to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[n][i]-1;o(` - Applied constant temperature to node ${r+1} (element ${n+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const t=this.boundaryConditions[e];"convection"===t[0]&&(d[e]=t[1],c[e]=t[2])})),"1D"===this.meshDimension?Object.keys(this.boundaryConditions).forEach((n=>{if("convection"===this.boundaryConditions[n][0]){const s=d[n],i=c[n];o(`Boundary ${n}: Applying convection with heat transfer coefficient h=${s} W/(m²·K) and external temperature T∞=${i} K`),this.boundaryElements[n].forEach((([n,r])=>{let a;"linear"===this.elementOrder?a=0===r?0:1:"quadratic"===this.elementOrder&&(a=0===r?0:2);const l=this.nop[n][a]-1;o(` - Applied convection boundary condition to node ${l+1} (element ${n+1}, local node ${a+1})`),e[l]+=-s*i,t[l][l]+=s}))}})):"2D"===this.meshDimension&&Object.keys(this.boundaryConditions).forEach((s=>{if("convection"===this.boundaryConditions[s][0]){const u=d[s],h=c[s];o(`Boundary ${s}: Applying convection with heat transfer coefficient h=${u} W/(m²·K) and external temperature T∞=${h} K`),this.boundaryElements[s].forEach((([s,d])=>{if("linear"===this.elementOrder){let c,m,f,p,y;0===d?(c=n[0],m=0,f=0,p=3,y=2):1===d?(c=0,m=n[0],f=0,p=2,y=1):2===d?(c=n[0],m=1,f=1,p=4,y=2):3===d&&(c=1,m=n[0],f=2,p=4,y=1);let b=l.getBasisFunctions(c,m),g=b.basisFunction,E=b.basisFunctionDerivKsi,v=b.basisFunctionDerivEta,M=0,$=0,x=0,C=0;const F=this.nop[s].length;for(let e=0;e{if("constantTemp"===t[e][0]){const n=t[e][1];switch(e){case"0":for(let e=0;eArray($).fill(0))),u=Array(M).fill(0),h=Array(M).fill(0),m=Array(M).fill(0),f=1;F.iwr1++;let p=1,y=1;A.nell=0;for(let e=0;e$||b>$)return void i("Error: nmax-nsum not large enough");for(let e=0;e0)for(let e=0;ey||A.nellMath.abs(l)&&(l=i,n=o,t=s)}}}let m=Math.abs(s[t-1]);e=Math.abs(w.lhed[n-1]);let y=m+e+u[m-1]+h[e-1];F.det=F.det*l*(-1)**y/Math.abs(l);for(let t=0;t=m&&u[t]--,t>=e&&h[t]--;if(Math.abs(l)<1e-10&&i(`Warning: matrix singular or ill-conditioned, nell=${A.nell}, kro=${m}, lco=${e}, pivot=${l}`),0===l)return;for(let e=0;e1)for(let e=0;e1&&0!==o)for(let t=0;t1)for(let t=0;t1||A.nellArray(9).fill(0))),xpt:Array(M).fill(0),ypt:Array(M).fill(0),ncod:Array(M).fill(0),bc:Array(M).fill(0),r1:Array(M).fill(0),u:Array(M).fill(0),ntop:Array(v).fill(0),nlat:Array(v).fill(0)},C={w:[.27777777777778,.444444444444,.27777777777778],gp:[.1127016654,.5,.8872983346]},F={iwr1:0,npt:0,ntra:0,nbn:Array(v).fill(0),det:1,sk:Array($*$).fill(0),ice1:0},A={estifm:Array(9).fill().map((()=>Array(9).fill(0))),nell:0},w={ecv:Array(2e6).fill(0),lhed:Array($).fill(0),qq:Array($).fill(0),ecpiv:Array(2e6).fill(0)},D=new l({meshDimension:"2D",elementOrder:"quadratic"});function N(){const e=A.nell-1,{estifm:t,localLoad:n,ngl:o}=function({elementIndex:e,nop:t,xCoordinates:n,yCoordinates:o,basisFunctions:s,gaussPoints:i,gaussWeights:r,ntopFlag:a=!1,nlatFlag:l=!1,convectionTop:d={active:!1,coeff:0,extTemp:0}}){const c=Array(9).fill().map((()=>Array(9).fill(0))),u=Array(9).fill(0),h=Array(9);for(let n=0;n<9;n++)h[n]=Math.abs(t[e][n]);for(let e=0;ee-1)),{detJacobian:m,basisFunctionDerivX:f,basisFunctionDerivY:y}=p({basisFunction:a,basisFunctionDerivKsi:l,basisFunctionDerivEta:d,nodesXCoordinates:n,nodesYCoordinates:o,localToGlobalMap:u,numNodes:9});for(let n=0;n<9;n++)for(let o=0;o<9;o++)c[n][o]-=r[e]*r[t]*m*(f[n]*f[o]+y[n]*y[o])}if(a&&d.active){const a=d.coeff,l=d.extTemp;for(let d=0;d0)continue;let r=0;w.qq[s-1]=0;for(let e=0;e"object"==typeof e&&null!==e||"function"==typeof e,v=new Map([["proxy",{canHandle:e=>M(e)&&e[g],serialize(e){const{port1:t,port2:n}=new MessageChannel;return C(e,t),[n,[n]]},deserialize:e=>(e.start(),S(e))}],["throw",{canHandle:e=>M(e)&&$ in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function C(e,t=globalThis,n=["*"]){t.addEventListener("message",(function o(s){if(!s||!s.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,s.origin))return void console.warn(`Invalid origin '${s.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},s.data),l=(s.data.argumentList||[]).map(T);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=T(s.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[g]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;C(e,n),d=function(e,t){return X.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[$]:0}}Promise.resolve(d).catch((e=>({value:e,[$]:0}))).then((n=>{const[s,a]=k(n);t.postMessage(Object.assign(Object.assign({},s),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",o),w(t),E in e&&"function"==typeof e[E]&&e[E]())})).catch((e=>{const[n,o]=k({value:new TypeError("Unserializable return value"),[$]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),o)}))})),t.start&&t.start()}function w(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function S(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const o=n.get(t.id);if(o)try{o(t)}finally{n.delete(t.id)}})),A(e,n,[],t)}function N(e){if(e)throw new Error("Proxy has been released and is not useable")}function x(e){return P(e,new Map,{type:"RELEASE"}).then((()=>{w(e)}))}const O=new WeakMap,D="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(O.get(e)||0)-1;O.set(e,t),0===t&&x(e)}));function A(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(N(s),r===b)return()=>{!function(e){D&&D.unregister(e)}(i),x(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=P(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(T);return o.then.bind(o)}return A(e,t,[...n,r])},set(o,i,r){N(s);const[a,l]=k(r);return P(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(T)},apply(o,i,r){N(s);const a=n[n.length-1];if(a===y)return P(e,t,{type:"ENDPOINT"}).then(T);if("bind"===a)return A(e,t,n.slice(0,-1));const[l,d]=F(r);return P(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(T)},construct(o,i){N(s);const[r,a]=F(i);return P(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(T)}});return function(e,t){const n=(O.get(t)||0)+1;O.set(t,n),D&&D.register(e,t,e)}(i,e),i}function F(e){const t=e.map(k);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const X=new WeakMap;function k(e){for(const[t,n]of v)if(n.canHandle(e)){const[o,s]=n.serialize(e);return[{type:"HANDLER",name:t,value:o},s]}return[{type:"RAW",value:e},X.get(e)||[]]}function T(e){switch(e.type){case"HANDLER":return v.get(e.name).deserialize(e.value);case"RAW":return e.value}}function P(e,t,n,o){return new Promise((s=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,s),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),o)}))}e.FEAScriptModel=class{constructor(){this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",s("FEAScriptModel instance created")}setSolverConfig(e){this.solverConfig=e,o(`Solver config set to: ${e}`)}setMeshConfig(e){this.meshConfig=e,o(`Mesh config set with dimensions: ${e.meshDimension}`)}addBoundaryCondition(e,t){this.boundaryConditions[e]=t,o(`Boundary condition added for boundary: ${e}, type: ${t[0]}`)}setSolverMethod(e){this.solverMethod=e,o(`Solver method set to: ${e}`)}solve(){if(!this.solverConfig||!this.meshConfig||!this.boundaryConditions){const e="Solver config, mesh config, and boundary conditions must be set before solving.";throw console.error(e),new Error(e)}let e=[],t=[],n=[],l=[],m={};if(s("Beginning solving process..."),console.time("totalSolvingTime"),"solidHeatTransferScript"===this.solverConfig){s(`Using solver: ${this.solverConfig}`),({jacobianMatrix:e,residualVector:t,nodesCoordinates:m}=function(e,t){s("Starting solid heat transfer matrix assembly...");const{meshDimension:n,numElementsX:r,numElementsY:a,maxX:l,maxY:m,elementOrder:f,parsedMesh:g}=e;let y;o("Generating mesh..."),"1D"===n?y=new h({numElementsX:r,maxX:l,elementOrder:f,parsedMesh:g}):"2D"===n?y=new u({numElementsX:r,maxX:l,numElementsY:a,maxY:m,elementOrder:f,parsedMesh:g}):i("Mesh dimension must be either '1D' or '2D'.");const b=y.boundaryElementsProcessed?y.parsedMesh:y.generateMesh();let E,$,M=b.nodesXCoordinates,v=b.nodesYCoordinates,C=b.totalNodesX,w=b.totalNodesY,S=b.nodalNumbering,N=b.boundaryElements;null!=g?(E=S.length,$=M.length,o(`Using parsed mesh with ${E} elements and ${$} nodes`)):(E=r*("2D"===n?a:1),$=C*("2D"===n?w:1),o(`Using mesh generated from geometry with ${E} elements and ${$} nodes`));let x,O,D,A,F,X,k,T=[],P=[],Y=[],R=[],W=[],I=[],B=[],j=[],q=[],V=[];for(let e=0;e<$;e++){q[e]=0,V.push([]);for(let t=0;t<$;t++)V[e][t]=0}const L=new d({meshDimension:n,elementOrder:f});let G=new c({meshDimension:n,elementOrder:f}).getGaussPointsAndWeights();P=G.gaussPoints,Y=G.gaussWeights;const U=S[0].length;for(let e=0;e0&&(i.initialSolution=[...n]);const s=a(f,i,100,1e-4);e=s.jacobianMatrix,t=s.residualVector,m=s.nodesCoordinates,n=s.solutionVector,o+=.2}}return console.timeEnd("totalSolvingTime"),s("Solving process completed"),{solutionVector:n,nodesCoordinates:m}}},e.FEAScriptWorker=class{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js","undefined"==typeof document&&"undefined"==typeof location?new(require("url").URL)("file:"+__filename).href:"undefined"==typeof document?location.href:document.currentScript&&"SCRIPT"===document.currentScript.tagName.toUpperCase()&&document.currentScript.src||new URL("feascript.umd.js",document.baseURI).href),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=S(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const o=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(o,1e3)};o()}))}async setSolverConfig(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),s("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),s(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),s("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return s(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}},e.VERSION="0.1.3",e.importGmshQuadTri=async e=>{let t={nodesXCoordinates:[],nodesYCoordinates:[],nodalNumbering:{quadElements:[],triangleElements:[]},boundaryElements:[],boundaryConditions:[],boundaryNodePairs:{},gmshV:0,ascii:!1,fltBytes:"8",totalNodesX:0,totalNodesY:0,physicalPropMap:[],elementTypes:{}},n=(await e.text()).split("\n").map((e=>e.trim())).filter((e=>""!==e&&" "!==e)),s="",i=0,r=0,a=0,l=0,d={numNodes:0},m=0,h=[],u=0,c=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},g=0,y={};for(;i""!==e));if("meshFormat"===s)t.gmshV=parseFloat(o[0]),t.ascii="0"===o[1],t.fltBytes=o[2];else if("physicalNames"===s){if(o.length>=3){if(!/^\d+$/.test(o[0])){i++;continue}const e=parseInt(o[0],10),n=parseInt(o[1],10);let s=o.slice(2).join(" ");s=s.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:n,dimension:e,name:s})}}else if("nodes"===s){if(0===r){r=parseInt(o[0],10),a=parseInt(o[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;y[n]||(y[n]=[]),y[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);g++,g===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=y[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),o(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t},e.logSystem=function(e){"basic"!==e&&"debug"!==e?(console.log("%c[WARN] Invalid log level: "+e+". Using basic instead.","color: #FFC107; font-weight: bold;"),n="basic"):(n=e,s(`Log level set to: ${e}`))},e.plotSolution=function(e,t,n,o,s,i,r="structured"){const{nodesXCoordinates:a,nodesYCoordinates:l}=t;if("1D"===o&&"line"===s){let t;t=e.length>0&&Array.isArray(e[0])?e.map((e=>e[0])):e;let o=Array.from(a),s={x:o,y:t,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},r=Math.min(window.innerWidth,700),l=Math.max(...o),d=r/l,m={title:`line plot - ${n}`,width:Math.max(d*l,400),height:350,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:70,r:40,t:50,b:50}};Plotly.newPlot(i,[s],m,{responsive:!0})}else if("2D"===o&&"contour"===s){const t="structured"===r,o=new Set(a).size,d=new Set(l).size;let m;m=Array.isArray(e[0])?e.map((e=>e[0])):e;let h=Math.min(window.innerWidth,700),u=Math.max(...a),c=Math.max(...l)/u,f=Math.min(h,600),p={title:`${s} plot - ${n}`,width:f,height:f*c*.8,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"};if(t){const t=o,n=d;math.reshape(Array.from(a),[t,n]);let s=math.reshape(Array.from(l),[t,n]),r=math.reshape(Array.from(e),[t,n]),m=math.transpose(r),h=[];for(let e=0;e"object"==typeof e&&null!==e||"function"==typeof e,P=new Map([["proxy",{canHandle:e=>Y(e)&&e[O],serialize(e){const{port1:t,port2:n}=new MessageChannel;return R(e,t),[n,[n]]},deserialize:e=>(e.start(),I(e))}],["throw",{canHandle:e=>Y(e)&&q in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function R(e,t=globalThis,n=["*"]){t.addEventListener("message",(function o(s){if(!s||!s.data)return;if(!function(e,t){for(const n of e){if(t===n||"*"===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}return!1}(n,s.origin))return void console.warn(`Invalid origin '${s.origin}' for comlink proxy`);const{id:i,type:r,path:a}=Object.assign({path:[]},s.data),l=(s.data.argumentList||[]).map(z);let d;try{const t=a.slice(0,-1).reduce(((e,t)=>e[t]),e),n=a.reduce(((e,t)=>e[t]),e);switch(r){case"GET":d=n;break;case"SET":t[a.slice(-1)[0]]=z(s.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[O]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;R(e,n),d=function(e,t){return J.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[q]:0}}Promise.resolve(d).catch((e=>({value:e,[q]:0}))).then((n=>{const[s,a]=U(n);t.postMessage(Object.assign(Object.assign({},s),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",o),W(t),k in e&&"function"==typeof e[k]&&e[k]())})).catch((e=>{const[n,o]=U({value:new TypeError("Unserializable return value"),[q]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),o)}))})),t.start&&t.start()}function W(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function I(e,t){const n=new Map;return e.addEventListener("message",(function(e){const{data:t}=e;if(!t||!t.id)return;const o=n.get(t.id);if(o)try{o(t)}finally{n.delete(t.id)}})),L(e,n,[],t)}function j(e){if(e)throw new Error("Proxy has been released and is not useable")}function B(e){return _(e,new Map,{type:"RELEASE"}).then((()=>{W(e)}))}const V=new WeakMap,G="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(V.get(e)||0)-1;V.set(e,t),0===t&&B(e)}));function L(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(j(s),r===T)return()=>{!function(e){G&&G.unregister(e)}(i),B(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=_(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(z);return o.then.bind(o)}return L(e,t,[...n,r])},set(o,i,r){j(s);const[a,l]=U(r);return _(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(z)},apply(o,i,r){j(s);const a=n[n.length-1];if(a===X)return _(e,t,{type:"ENDPOINT"}).then(z);if("bind"===a)return L(e,t,n.slice(0,-1));const[l,d]=K(r);return _(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(z)},construct(o,i){j(s);const[r,a]=K(i);return _(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(z)}});return function(e,t){const n=(V.get(t)||0)+1;V.set(t,n),G&&G.register(e,t,e)}(i,e),i}function K(e){const t=e.map(U);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const J=new WeakMap;function U(e){for(const[t,n]of P)if(n.canHandle(e)){const[o,s]=n.serialize(e);return[{type:"HANDLER",name:t,value:o},s]}return[{type:"RAW",value:e},J.get(e)||[]]}function z(e){switch(e.type){case"HANDLER":return P.get(e.name).deserialize(e.value);case"RAW":return e.value}}function _(e,t,n,o){return new Promise((s=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,s),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),o)}))}e.FEAScriptModel=class{constructor(){this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",s("FEAScriptModel instance created")}setSolverConfig(e){this.solverConfig=e,o(`Solver config set to: ${e}`)}setMeshConfig(e){this.meshConfig=e,o(`Mesh config set with dimensions: ${e.meshDimension}`)}addBoundaryCondition(e,t){this.boundaryConditions[e]=t,o(`Boundary condition added for boundary: ${e}, type: ${t[0]}`)}setSolverMethod(e){this.solverMethod=e,o(`Solver method set to: ${e}`)}solve(){if(!this.solverConfig||!this.meshConfig||!this.boundaryConditions){const e="Solver config, mesh config, and boundary conditions must be set before solving.";throw console.error(e),new Error(e)}let e=[],t=[],n=[],l=[];s("Preparing mesh...");const d=function(e){const{meshDimension:t,numElementsX:n,numElementsY:s,maxX:r,maxY:a,elementOrder:l,parsedMesh:d}=e;let h;"1D"===t?h=new c({numElementsX:n,maxX:r,elementOrder:l,parsedMesh:d}):"2D"===t?h=new u({numElementsX:n,maxX:r,numElementsY:s,maxY:a,elementOrder:l,parsedMesh:d}):i("Mesh dimension must be either '1D' or '2D'.");const m=h.boundaryElementsProcessed?h.parsedMesh:h.generateMesh();let f,p,y=m.nodesXCoordinates,b=m.nodesYCoordinates,g=m.totalNodesX,E=m.totalNodesY,v=m.nodalNumbering,M=m.boundaryElements;return null!=d?(f=v.length,p=y.length,o(`Using parsed mesh with ${f} elements and ${p} nodes`)):(f=n*("2D"===t?s:1),p=g*("2D"===t?E:1),o(`Using mesh generated from geometry with ${f} elements and ${p} nodes`)),{nodesXCoordinates:y,nodesYCoordinates:b,totalNodesX:g,totalNodesY:E,nop:v,boundaryElements:M,totalElements:f,totalNodes:p,meshDimension:t,elementOrder:l}}(this.meshConfig);s("Mesh preparation completed");const h={nodesXCoordinates:d.nodesXCoordinates,nodesYCoordinates:d.nodesYCoordinates};if(s("Beginning solving process..."),console.time("totalSolvingTime"),"solidHeatTransferScript"===this.solverConfig)if(s(`Using solver: ${this.solverConfig}`),"frontal"===this.solverMethod){s("Using frontal solver method");n=E(this.meshConfig,this.boundaryConditions).solutionVector}else{({jacobianMatrix:e,residualVector:t}=function(e,t){s("Starting solid heat transfer matrix assembly...");const{nodesXCoordinates:n,nodesYCoordinates:i,nop:r,boundaryElements:a,totalElements:l,meshDimension:d,elementOrder:c}=e,u=m(e),{residualVector:h,jacobianMatrix:y,localToGlobalMap:b,basisFunctions:E,gaussPoints:v,gaussWeights:M,numNodes:$}=u;for(let e=0;e0&&(r.initialSolution=[...n]);const s=a(b,r,100,1e-4);e=s.jacobianMatrix,t=s.residualVector,n=s.solutionVector,o+=1/i}}return console.timeEnd("totalSolvingTime"),s("Solving process completed"),{solutionVector:n,nodesCoordinates:h}}},e.FEAScriptWorker=class{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js","undefined"==typeof document&&"undefined"==typeof location?new(require("url").URL)("file:"+__filename).href:"undefined"==typeof document?location.href:document.currentScript&&"SCRIPT"===document.currentScript.tagName.toUpperCase()&&document.currentScript.src||new URL("feascript.umd.js",document.baseURI).href),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=I(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const o=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(o,1e3)};o()}))}async setSolverConfig(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),s("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),s(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),s("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return s(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}},e.VERSION="0.1.3",e.importGmshQuadTri=async e=>{let t={nodesXCoordinates:[],nodesYCoordinates:[],nodalNumbering:{quadElements:[],triangleElements:[]},boundaryElements:[],boundaryConditions:[],boundaryNodePairs:{},gmshV:0,ascii:!1,fltBytes:"8",totalNodesX:0,totalNodesY:0,physicalPropMap:[],elementTypes:{}},n=(await e.text()).split("\n").map((e=>e.trim())).filter((e=>""!==e&&" "!==e)),s="",i=0,r=0,a=0,l=0,d={numNodes:0},c=0,u=[],h=0,m=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},y=0,b={};for(;i""!==e));if("meshFormat"===s)t.gmshV=parseFloat(o[0]),t.ascii="0"===o[1],t.fltBytes=o[2];else if("physicalNames"===s){if(o.length>=3){if(!/^\d+$/.test(o[0])){i++;continue}const e=parseInt(o[0],10),n=parseInt(o[1],10);let s=o.slice(2).join(" ");s=s.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:n,dimension:e,name:s})}}else if("nodes"===s){if(0===r){r=parseInt(o[0],10),a=parseInt(o[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;b[n]||(b[n]=[]),b[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);y++,y===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=b[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),o(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t},e.logSystem=function(e){"basic"!==e&&"debug"!==e?(console.log("%c[WARN] Invalid log level: "+e+". Using basic instead.","color: #FFC107; font-weight: bold;"),n="basic"):(n=e,s(`Log level set to: ${e}`))},e.plotSolution=function(e,t,n,o,s,i,r="structured"){const{nodesXCoordinates:a,nodesYCoordinates:l}=t;if("1D"===o&&"line"===s){let t;t=e.length>0&&Array.isArray(e[0])?e.map((e=>e[0])):e;let o=Array.from(a),s={x:o,y:t,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},r=Math.min(window.innerWidth,700),l=Math.max(...o),d=r/l,c={title:`line plot - ${n}`,width:Math.max(d*l,400),height:350,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:70,r:40,t:50,b:50}};Plotly.newPlot(i,[s],c,{responsive:!0})}else if("2D"===o&&"contour"===s){const t="structured"===r,o=new Set(a).size,d=new Set(l).size;let c;c=Array.isArray(e[0])?e.map((e=>e[0])):e;let u=Math.min(window.innerWidth,700),h=Math.max(...a),m=Math.max(...l)/h,f=Math.min(u,600),p={title:`${s} plot - ${n}`,width:f,height:f*m*.8,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"};if(t){const t=o,n=d;math.reshape(Array.from(a),[t,n]);let s=math.reshape(Array.from(l),[t,n]),r=math.reshape(Array.from(e),[t,n]),c=math.transpose(r),u=[];for(let e=0;e 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n nodesCoordinates,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Helper function to calculate system size from mesh configuration\n * @param {object} meshConfig - Mesh configuration object\n * @returns {number} Total number of nodes in the system\n */\nexport function calculateSystemSize(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, elementOrder, parsedMesh } = meshConfig;\n\n if (parsedMesh && parsedMesh.nodesXCoordinates) {\n // For parsed meshes (like from GMSH)\n return parsedMesh.nodesXCoordinates.length;\n } else {\n // For geometry-based meshes\n let nodesX,\n nodesY = 1;\n\n if (elementOrder === \"linear\") {\n nodesX = numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = numElementsY + 1;\n } else if (elementOrder === \"quadratic\") {\n nodesX = 2 * numElementsX + 1;\n if (meshDimension === \"2D\") nodesY = 2 * numElementsY + 1;\n }\n\n return nodesX * nodesY;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n debugLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n if (\n this.numElementsX === null ||\n this.maxX === null ||\n this.numElementsY === null ||\n this.maxY === null\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n \n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\n\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the front propagation matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation (ranges from 0 to 1)\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleFrontPropagationMat(\n meshConfig,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n // TODO: The mesh generation step should be moved outside of the assembleFrontPropagationMat function so that not performed in every Newton-Raphson iteration\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n let solutionDerivX; // The x-derivative of the solution\n let solutionDerivY; // The y-derivative of the solution\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n detJacobian = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n detJacobian = ksiDerivX;\n }\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n // 2D front propagation (eikonal) equation\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n solutionDerivX = 0;\n solutionDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x & y-derivatives of basis functions and x & y-derivatives of the solution\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n // The x-derivative of the solution\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n // The y-derivative of the solution\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector - Viscous term: Add diffusion contribution to stabilize the solution\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n // residualVector - Eikonal term: Add the eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix - Viscous term: Add the Jacobian contribution from the diffusion term\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n // jacobianMatrix - Eikonal term: Add the Jacobian contribution from the eikonal equation\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n (detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)\n ) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n }\n\n // Create an instance of GenericBoundaryConditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions (Dirichlet type)\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions (Robin type)\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n let nodesCoordinates = {};\n let eikonalExteralIterations = 5; // Number of incremental steps to gradually activate the eikonal term - Used in frontPropagationScript\n let newtonRaphsonIterations;\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n ({ jacobianMatrix, residualVector, nodesCoordinates } = assembleSolidHeatTransferMat(\n this.meshConfig,\n this.boundaryConditions\n ));\n\n // Solve the assembled linear system\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n\n // Create context object with all necessary properties\n const context = {\n meshConfig: this.meshConfig,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n nodesCoordinates = newtonRaphsonResult.nodesCoordinates;\n solutionVector = newtonRaphsonResult.solutionVector;\n newtonRaphsonIterations = newtonRaphsonResult.iterations;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"../mesh/meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the solid heat transfer matrix\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n * - nodesCoordinates: Object containing x and y coordinates of nodes\n */\nexport function assembleSolidHeatTransferMat(meshConfig, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh details from the configuration object\n const {\n meshDimension, // The dimension of the mesh\n numElementsX, // Number of elements in x-direction\n numElementsY, // Number of elements in y-direction (only for 2D)\n maxX, // Max x-coordinate (m) of the domain\n maxY, // Max y-coordinate (m) of the domain (only for 2D)\n elementOrder, // The order of elements\n parsedMesh, // The pre-parsed mesh data (if available)\n } = meshConfig;\n\n // Create a new instance of the Mesh class\n debugLog(\"Generating mesh...\");\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n\n // Debug log for mesh size\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n // Debug log for mesh size\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n // Initialize variables for matrix assembly\n let localToGlobalMap = []; // Maps local element node indices to global mesh node indices\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n let basisFunction = []; // Basis functions\n let basisFunctionDerivKsi = []; // Derivatives of basis functions with respect to ksi\n let basisFunctionDerivEta = []; // Derivatives of basis functions with respect to eta (only for 2D)\n let basisFunctionDerivX = []; // The x-derivative of the basis function\n let basisFunctionDerivY = []; // The y-derivative of the basis function (only for 2D)\n let residualVector = []; // Galerkin residuals\n let jacobianMatrix = []; // Jacobian matrix\n let xCoordinates; // x-coordinate (physical coordinates)\n let yCoordinates; // y-coordinate (physical coordinates) (only for 2D)\n let ksiDerivX; // ksi-derivative of xCoordinates\n let etaDerivX; // eta-derivative of xCoordinates (ksi and eta are natural coordinates that vary within a reference element) (only for 2D)\n let ksiDerivY; // ksi-derivative of yCoordinates (only for 2D)\n let etaDerivY; // eta-derivative of yCoordinates (only for 2D)\n let detJacobian; // The Jacobian of the isoparametric mapping\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n gaussPoints = gaussPointsAndWeights.gaussPoints;\n gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n xCoordinates = 0;\n ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; // The x-derivative of the n basis function\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n // 2D solid heat transfer\n } else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Initialise variables for isoparametric mapping\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n basisFunction = basisFunctionsAndDerivatives.basisFunction;\n basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n xCoordinates = 0;\n yCoordinates = 0;\n ksiDerivX = 0;\n etaDerivX = 0;\n ksiDerivY = 0;\n etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX +=\n nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY +=\n nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Create an instance of ThermalBoundaryConditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n nodesCoordinates: {\n nodesXCoordinates,\n nodesYCoordinates,\n },\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.3\";","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","debugLog","message","console","log","basicLog","errorLog","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","math","lusolve","jacobiSolverResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiSolver","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","nodesCoordinates","totalNodes","meshConfig","meshDimension","numElementsX","numElementsY","elementOrder","parsedMesh","nodesXCoordinates","nodesX","nodesY","calculateSystemSize","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","GenericBoundaryConditions","constructor","boundaryElements","nop","this","imposeConstantValueBoundaryConditions","Object","keys","forEach","boundaryKey","value","elementIndex","side","nodeIndex","globalNodeIndex","colIndex","BasisFunctions","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","maxX","maxY","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","undefined","fixedBoundaryElements","boundaryNodePairs","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","generate1DNodalNumbering","findBoundaryElements","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","assembleFrontPropagationMat","eikonalViscousTerm","mesh","nodesCoordinatesAndNumbering","totalElements","xCoordinates","yCoordinates","ksiDerivX","etaDerivX","ksiDerivY","etaDerivY","detJacobian","solutionDerivX","solutionDerivY","localToGlobalMap","basisFunctionDerivX","basisFunctionDerivY","basisFunctions","gaussPointsAndWeights","numNodes","localNodeIndex","gaussPointIndex1","basisFunctionsAndDerivatives","gaussPointIndex2","localNodeIndex1","localToGlobalMap1","localNodeIndex2","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","Error","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","map","fromWireValue","returnValue","parent","slice","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","r","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","arr","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","thermalBoundaryConditions","assembleSolidHeatTransferMat","newtonRaphsonResult","worker","feaWorker","isReady","_initWorker","Worker","URL","document","location","require","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","result","toFixed","getModelInfo","ping","terminate","async","file","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","parseInt","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","level","plotType","plotDivId","meshType","yData","xData","from","lineData","mode","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","l","t","b","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"feascript.umd.js","sources":["../src/methods/euclideanNormScript.js","../src/utilities/loggingScript.js","../src/methods/linearSystemSolverScript.js","../src/methods/jacobiSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/mesh/basisFunctionsScript.js","../src/mesh/meshGenerationScript.js","../src/methods/numericalIntegrationScript.js","../src/mesh/meshUtilsScript.js","../src/solvers/genericBoundaryConditionsScript.js","../src/solvers/frontPropagationScript.js","../src/solvers/thermalBoundaryConditionsScript.js","../src/methods/frontalSolverScript.js","../src/solvers/solidHeatTransferScript.js","../src/vendor/comlink.mjs","../src/FEAScript.js","../src/workers/workerScript.js","../src/index.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.js"],"sourcesContent":["// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to calculate the Euclidean norm of a vector\n * @param {array} vector - The input vector\n * @returns {number} The Euclidean norm of the vector\n */\nexport function euclideanNorm(vector) {\n let norm = 0;\n for (let i = 0; i < vector.length; i++) {\n norm += vector[i] * vector[i];\n }\n norm = Math.sqrt(norm);\n return norm;\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Global logging level\nlet currentLogLevel = \"basic\";\n\n/**\n * Function to set the logging system level\n * @param {string} level - Logging level (basic, debug)\n */\nexport function logSystem(level) {\n if (level !== \"basic\" && level !== \"debug\") {\n console.log(\n \"%c[WARN] Invalid log level: \" + level + \". Using basic instead.\",\n \"color: #FFC107; font-weight: bold;\"\n ); // Yellow for warnings\n currentLogLevel = \"basic\";\n } else {\n currentLogLevel = level;\n basicLog(`Log level set to: ${level}`);\n }\n}\n\n/**\n * Function to log debug messages - only logs if level is 'debug'\n * @param {string} message - Message to log\n */\nexport function debugLog(message) {\n if (currentLogLevel === \"debug\") {\n console.log(\"%c[DEBUG] \" + message, \"color: #2196F3; font-weight: bold;\"); // Blue color for debug\n }\n}\n\n/**\n * Function to log basic information - always logs\n * @param {string} message - Message to log\n */\nexport function basicLog(message) {\n console.log(\"%c[INFO] \" + message, \"color: #4CAF50; font-weight: bold;\"); // Green color for basic info\n}\n\n/**\n * Function to log error messages\n * @param {string} message - Message to log\n */\nexport function errorLog(message) {\n console.log(\"%c[ERROR] \" + message, \"color: #F44336; font-weight: bold;\"); // Red color for errors\n}\n\n/**\n * Function to handle version information and fetch the latest update date and release from GitHub\n */\nexport async function printVersion() {\n basicLog(\"Fetching latest FEAScript version information...\");\n try {\n const commitResponse = await fetch(\"https://api.github.com/repos/FEAScript/FEAScript/commits/main\");\n const commitData = await commitResponse.json();\n const latestCommitDate = new Date(commitData.commit.committer.date).toLocaleString();\n basicLog(`Latest FEAScript update: ${latestCommitDate}`);\n return latestCommitDate;\n } catch (error) {\n errorLog(\"Failed to fetch version information: \" + error);\n return \"Version information unavailable\";\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { jacobiSolver } from \"./jacobiSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to solve a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (\"lusolve\" or \"jacobi\")\n * @param {Array} jacobianMatrix - The coefficient matrix\n * @param {Array} residualVector - The right-hand side vector\n * @param {object} [options] - Additional options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum iterations for iterative methods\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance for iterative methods\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - converged: Boolean indicating whether the method converged (for iterative methods)\n * - iterations: Number of iterations performed (for iterative methods)\n */\nexport function solveLinearSystem(solverMethod, jacobianMatrix, residualVector, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n\n let solutionVector = [];\n let converged = true;\n let iterations = 0;\n\n // Solve the linear system based on the specified solver method\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n if (solverMethod === \"lusolve\") {\n // Use LU decomposition method\n const jacobianMatrixSparse = math.sparse(jacobianMatrix);\n const luFactorization = math.slu(jacobianMatrixSparse, 1, 1); // order=1, threshold=1 for pivoting\n let solutionMatrix = math.lusolve(luFactorization, residualVector);\n solutionVector = math.squeeze(solutionMatrix).valueOf();\n //solutionVector = math.lusolve(jacobianMatrix, residualVector); // In the case of a dense matrix\n } else if (solverMethod === \"jacobi\") {\n // Use Jacobi method\n const initialGuess = new Array(residualVector.length).fill(0);\n const jacobiSolverResult = jacobiSolver(jacobianMatrix, residualVector, initialGuess, {\n maxIterations,\n tolerance,\n });\n\n // Log convergence information\n if (jacobiSolverResult.converged) {\n debugLog(`Jacobi method converged in ${jacobiSolverResult.iterations} iterations`);\n } else {\n debugLog(`Jacobi method did not converge after ${jacobiSolverResult.iterations} iterations`);\n }\n\n solutionVector = jacobiSolverResult.solutionVector;\n converged = jacobiSolverResult.converged;\n iterations = jacobiSolverResult.iterations;\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n return { solutionVector, converged, iterations };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method\n * @param {array} jacobianMatrix - The coefficient matrix (must be square)\n * @param {array} residualVector - The right-hand side vector\n * @param {array} initialGuess - Initial guess for solution vector\n * @param {object} [options] - Options for the solver\n * @param {number} [options.maxIterations=1000] - Maximum number of iterations\n * @param {number} [options.tolerance=1e-6] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\nexport function jacobiSolver(jacobianMatrix, residualVector, initialGuess, options = {}) {\n const { maxIterations = 1000, tolerance = 1e-6 } = options;\n const n = jacobianMatrix.length; // Size of the square matrix\n let x = [...initialGuess]; // Current solution (starts with initial guess)\n let xNew = new Array(n); // Next iteration's solution\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n // Perform one iteration\n for (let i = 0; i < n; i++) {\n let sum = 0;\n // Calculate sum of jacobianMatrix[i][j] * x[j] for j ≠ i\n for (let j = 0; j < n; j++) {\n if (j !== i) {\n sum += jacobianMatrix[i][j] * x[j];\n }\n }\n // Update xNew[i] using the Jacobi formula\n xNew[i] = (residualVector[i] - sum) / jacobianMatrix[i][i];\n }\n\n // Check convergence\n let maxDiff = 0;\n for (let i = 0; i < n; i++) {\n maxDiff = Math.max(maxDiff, Math.abs(xNew[i] - x[i]));\n }\n\n // Update x for next iteration\n x = [...xNew];\n\n // Successfully converged if maxDiff is less than tolerance\n if (maxDiff < tolerance) {\n return {\n solutionVector: x,\n iterations: iteration + 1,\n converged: true,\n };\n }\n }\n\n // maxIterations were reached without convergence\n return {\n solutionVector: x,\n iterations: maxIterations,\n converged: false,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { euclideanNorm } from \"../methods/euclideanNormScript.js\";\nimport { solveLinearSystem } from \"./linearSystemSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to solve a system of non-linear equations using the Newton-Raphson method\n * @param {number} [maxIterations=100] - Maximum number of iterations\n * @param {number} [tolerance=1e-4] - Convergence tolerance\n * @returns {object} An object containing:\n * - solutionVector: The solution vector\n * - iterations: The number of iterations performed\n * - converged: Boolean indicating whether the method converged\n */\n\nexport function newtonRaphson(assembleMat, context, maxIterations = 100, tolerance = 1e-4) {\n let errorNorm = 0;\n let converged = false;\n let iterations = 0;\n let deltaX = [];\n let solutionVector = [];\n let jacobianMatrix = [];\n let residualVector = [];\n\n // Calculate system size from meshData instead of meshConfig\n let totalNodes = context.meshData.nodesXCoordinates.length;\n\n // Initialize arrays with proper size\n for (let i = 0; i < totalNodes; i++) {\n deltaX[i] = 0;\n solutionVector[i] = 0;\n }\n\n // Initialize solution from context if available\n if (context.initialSolution && context.initialSolution.length === totalNodes) {\n solutionVector = [...context.initialSolution];\n }\n\n while (iterations < maxIterations && !converged) {\n // Update solution\n for (let i = 0; i < solutionVector.length; i++) {\n solutionVector[i] = Number(solutionVector[i]) + Number(deltaX[i]);\n }\n\n // Compute Jacobian and residual matrices\n ({ jacobianMatrix, residualVector } = assembleMat(\n context.meshData,\n context.boundaryConditions,\n solutionVector, // The solution vector is required in the case of a non-linear equation\n context.eikonalActivationFlag // Currently used only in the front propagation solver (TODO refactor in case of a solver not needing it)\n ));\n\n // Solve the linear system based on the specified solver method\n const linearSystemResult = solveLinearSystem(context.solverMethod, jacobianMatrix, residualVector);\n deltaX = linearSystemResult.solutionVector;\n\n // Check convergence\n errorNorm = euclideanNorm(deltaX);\n\n // Norm for each iteration\n basicLog(`Newton-Raphson iteration ${iterations + 1}: Error norm = ${errorNorm.toExponential(4)}`);\n\n if (errorNorm <= tolerance) {\n converged = true;\n } else if (errorNorm > 1e2) {\n errorLog(`Solution not converged. Error norm: ${errorNorm}`);\n break;\n }\n\n iterations++;\n }\n\n return {\n solutionVector,\n converged,\n iterations,\n jacobianMatrix,\n residualVector,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle basis functions and their derivatives based on element configuration\n */\nexport class BasisFunctions {\n /**\n * Constructor to initialize the BasisFunctions class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to calculate basis functions and their derivatives based on the dimension and order\n * @param {number} ksi - Natural coordinate (for both 1D and 2D)\n * @param {number} [eta] - Second natural coordinate (only for 2D elements)\n * @returns {object} An object containing:\n * - basisFunction: Array of evaluated basis functions\n * - basisFunctionDerivKsi: Array of derivatives of basis functions with respect to ksi\n * - basisFunctionDerivEta: Array of derivatives of basis functions with respect to eta (only for 2D elements)\n */\n getBasisFunctions(ksi, eta = null) {\n let basisFunction = [];\n let basisFunctionDerivKsi = [];\n let basisFunctionDerivEta = [];\n\n if (this.meshDimension === \"1D\") {\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 1D elements\n basisFunction[0] = 1 - ksi;\n basisFunction[1] = ksi;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -1;\n basisFunctionDerivKsi[1] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 1D elements\n basisFunction[0] = 1 - 3 * ksi + 2 * ksi ** 2;\n basisFunction[1] = 4 * ksi - 4 * ksi ** 2;\n basisFunction[2] = -ksi + 2 * ksi ** 2;\n\n // Derivatives of basis functions with respect to ksi\n basisFunctionDerivKsi[0] = -3 + 4 * ksi;\n basisFunctionDerivKsi[1] = 4 - 8 * ksi;\n basisFunctionDerivKsi[2] = -1 + 4 * ksi;\n }\n } else if (this.meshDimension === \"2D\") {\n if (eta === null) {\n errorLog(\"Eta coordinate is required for 2D elements\");\n return;\n }\n\n if (this.elementOrder === \"linear\") {\n // Linear basis functions for 2D elements\n function l1(c) {\n return 1 - c;\n }\n function l2(c) {\n return c;\n }\n function dl1() {\n return -1;\n }\n function dl2() {\n return 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l2(ksi) * l1(eta);\n basisFunction[3] = l2(ksi) * l2(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1() * l1(eta);\n basisFunctionDerivKsi[1] = dl1() * l2(eta);\n basisFunctionDerivKsi[2] = dl2() * l1(eta);\n basisFunctionDerivKsi[3] = dl2() * l2(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1();\n basisFunctionDerivEta[1] = l1(ksi) * dl2();\n basisFunctionDerivEta[2] = l2(ksi) * dl1();\n basisFunctionDerivEta[3] = l2(ksi) * dl2();\n } else if (this.elementOrder === \"quadratic\") {\n // Quadratic basis functions for 2D elements\n function l1(c) {\n return 2 * c ** 2 - 3 * c + 1;\n }\n function l2(c) {\n return -4 * c ** 2 + 4 * c;\n }\n function l3(c) {\n return 2 * c ** 2 - c;\n }\n function dl1(c) {\n return 4 * c - 3;\n }\n function dl2(c) {\n return -8 * c + 4;\n }\n function dl3(c) {\n return 4 * c - 1;\n }\n\n // Evaluate basis functions at (ksi, eta)\n basisFunction[0] = l1(ksi) * l1(eta);\n basisFunction[1] = l1(ksi) * l2(eta);\n basisFunction[2] = l1(ksi) * l3(eta);\n basisFunction[3] = l2(ksi) * l1(eta);\n basisFunction[4] = l2(ksi) * l2(eta);\n basisFunction[5] = l2(ksi) * l3(eta);\n basisFunction[6] = l3(ksi) * l1(eta);\n basisFunction[7] = l3(ksi) * l2(eta);\n basisFunction[8] = l3(ksi) * l3(eta);\n\n // Derivatives with respect to ksi\n basisFunctionDerivKsi[0] = dl1(ksi) * l1(eta);\n basisFunctionDerivKsi[1] = dl1(ksi) * l2(eta);\n basisFunctionDerivKsi[2] = dl1(ksi) * l3(eta);\n basisFunctionDerivKsi[3] = dl2(ksi) * l1(eta);\n basisFunctionDerivKsi[4] = dl2(ksi) * l2(eta);\n basisFunctionDerivKsi[5] = dl2(ksi) * l3(eta);\n basisFunctionDerivKsi[6] = dl3(ksi) * l1(eta);\n basisFunctionDerivKsi[7] = dl3(ksi) * l2(eta);\n basisFunctionDerivKsi[8] = dl3(ksi) * l3(eta);\n\n // Derivatives with respect to eta\n basisFunctionDerivEta[0] = l1(ksi) * dl1(eta);\n basisFunctionDerivEta[1] = l1(ksi) * dl2(eta);\n basisFunctionDerivEta[2] = l1(ksi) * dl3(eta);\n basisFunctionDerivEta[3] = l2(ksi) * dl1(eta);\n basisFunctionDerivEta[4] = l2(ksi) * dl2(eta);\n basisFunctionDerivEta[5] = l2(ksi) * dl3(eta);\n basisFunctionDerivEta[6] = l3(ksi) * dl1(eta);\n basisFunctionDerivEta[7] = l3(ksi) * dl2(eta);\n basisFunctionDerivEta[8] = l3(ksi) * dl3(eta);\n }\n }\n\n return { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Basic structure for the mesh\n */\nexport class Mesh {\n /**\n * Constructor to initialize the Mesh class\n * @param {object} config - Configuration object for the mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY=1] - Number of elements along the y-axis (for 1D meshes)\n * @param {number} [config.maxY=0] - Maximum y-coordinate of the mesh (for 1D meshes)\n * @param {string} [config.meshDimension='2D'] - The dimension of the mesh, either 1D or 2D\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n meshDimension = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n this.numElementsX = numElementsX;\n this.numElementsY = numElementsY;\n this.maxX = maxX;\n this.maxY = maxY;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n this.parsedMesh = parsedMesh;\n\n this.boundaryElementsProcessed = false;\n\n if (this.parsedMesh) {\n basicLog(\"Using pre-parsed mesh from gmshReader data for mesh generation.\");\n this.parseMeshFromGmsh();\n }\n }\n\n /**\n * Method to parse the mesh from the GMSH format to the FEAScript format\n */\n parseMeshFromGmsh() {\n if (!this.parsedMesh.nodalNumbering) {\n errorLog(\"No valid nodal numbering found in the parsed mesh.\");\n }\n\n if (\n typeof this.parsedMesh.nodalNumbering === \"object\" &&\n !Array.isArray(this.parsedMesh.nodalNumbering)\n ) {\n // Store the nodal numbering structure before converting\n const quadElements = this.parsedMesh.nodalNumbering.quadElements || [];\n const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || [];\n\n debugLog(\n \"Initial parsed mesh nodal numbering from GMSH format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Check if it has quadElements or triangleElements structure from gmshReader\n if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) {\n // Map nodal numbering from GMSH format to FEAScript format for quad elements\n const mappedNodalNumbering = [];\n\n for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) {\n const gmshNodes = quadElements[elemIdx];\n const feaScriptNodes = new Array(gmshNodes.length);\n\n // Check for element type based on number of nodes\n if (gmshNodes.length === 4) {\n // Simple mapping for linear quad elements (4 nodes)\n // GMSH: FEAScript:\n // 3 --- 2 1 --- 3\n // | | --> | |\n // 0 --- 1 0 --- 2\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1\n feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2\n feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3\n } else if (gmshNodes.length === 9) {\n // Mapping for quadratic quad elements (9 nodes)\n // GMSH: FEAScript:\n // 3--6--2 2--5--8\n // | | | |\n // 7 8 5 --> 1 4 7\n // | | | |\n // 0--4--1 0--3--6\n\n feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0\n feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1\n feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2\n feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3\n feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4\n feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5\n feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6\n feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7\n feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8\n }\n\n mappedNodalNumbering.push(feaScriptNodes);\n }\n\n this.parsedMesh.nodalNumbering = mappedNodalNumbering;\n } else if (this.parsedMesh.elementTypes[2]) {\n errorLog(\"Element type is neither triangle nor quad; mapping for this type is not implemented yet.\");\n }\n\n debugLog(\n \"Nodal numbering after mapping from GMSH to FEAScript format: \" +\n JSON.stringify(this.parsedMesh.nodalNumbering)\n );\n\n // Process boundary elements if they exist and if physical property mapping exists\n if (this.parsedMesh.physicalPropMap && this.parsedMesh.boundaryElements) {\n // Check if boundary elements need to be processed\n if (\n Array.isArray(this.parsedMesh.boundaryElements) &&\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n // Create a new array without the empty first element\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n\n // If boundary node pairs exist but boundary elements haven't been processed\n if (this.parsedMesh.boundaryNodePairs && !this.parsedMesh.boundaryElementsProcessed) {\n // Reset boundary elements array\n this.parsedMesh.boundaryElements = [];\n\n // Process each physical property from the Gmsh file\n this.parsedMesh.physicalPropMap.forEach((prop) => {\n // Only process 1D physical entities (boundary lines)\n if (prop.dimension === 1) {\n // Get all node pairs for this boundary\n const boundaryNodePairs = this.parsedMesh.boundaryNodePairs[prop.tag] || [];\n\n if (boundaryNodePairs.length > 0) {\n // Initialize array for this boundary tag\n if (!this.parsedMesh.boundaryElements[prop.tag]) {\n this.parsedMesh.boundaryElements[prop.tag] = [];\n }\n\n // For each boundary line segment (defined by a pair of nodes)\n boundaryNodePairs.forEach((nodesPair) => {\n const node1 = nodesPair[0]; // First node in the pair\n const node2 = nodesPair[1]; // Second node in the pair\n\n debugLog(\n `Processing boundary node pair: [${node1}, ${node2}] for boundary ${prop.tag} (${\n prop.name || \"unnamed\"\n })`\n );\n\n // Search through all elements to find which one contains both nodes\n let foundElement = false;\n\n // Loop through all elements in the mesh\n for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) {\n const elemNodes = this.parsedMesh.nodalNumbering[elemIdx];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elemNodes.length === 4) {\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript linear quadrilateral numbering:\n // 1 --- 3\n // | |\n // 0 --- 2\n\n if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0)\n ) {\n side = 0; // Bottom side\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0)\n ) {\n side = 1; // Left side\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 1 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 1)\n ) {\n side = 2; // Top side\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 2)\n ) {\n side = 3; // Right side\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elemNodes.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elemNodes.includes(node1) && elemNodes.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elemNodes.indexOf(node1);\n const node2Index = elemNodes.indexOf(node2);\n\n debugLog(\n ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join(\n \", \"\n )}]`\n );\n debugLog(\n ` Node ${node1} is at index ${node1Index}, Node ${node2} is at index ${node2Index} in the element`\n );\n\n // Based on FEAScript quadratic quadrilateral numbering:\n // 2--5--8\n // | |\n // 1 4 7\n // | |\n // 0--3--6\n\n // TODO: Transform into dictionaries for better readability\n if (\n (node1Index === 0 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 3) ||\n (node1Index === 3 && node2Index === 0) ||\n (node1Index === 3 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 3)\n ) {\n side = 0; // Bottom side (nodes 0, 3, 6)\n debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 0 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 0) ||\n (node1Index === 0 && node2Index === 1) ||\n (node1Index === 1 && node2Index === 0) ||\n (node1Index === 1 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 1)\n ) {\n side = 1; // Left side (nodes 0, 1, 2)\n debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 2 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 2) ||\n (node1Index === 2 && node2Index === 5) ||\n (node1Index === 5 && node2Index === 2) ||\n (node1Index === 5 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 5)\n ) {\n side = 2; // Top side (nodes 2, 5, 8)\n debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`);\n } else if (\n (node1Index === 6 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 6) ||\n (node1Index === 6 && node2Index === 7) ||\n (node1Index === 7 && node2Index === 6) ||\n (node1Index === 7 && node2Index === 8) ||\n (node1Index === 8 && node2Index === 7)\n ) {\n side = 3; // Right side (nodes 6, 7, 8)\n debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]);\n debugLog(\n ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n }\n }\n\n if (!foundElement) {\n errorLog(\n `Could not find element containing boundary nodes ${node1} and ${node2}. Boundary may be incomplete.`\n );\n }\n });\n }\n }\n });\n\n // Mark as processed\n this.boundaryElementsProcessed = true;\n\n // Fix boundary elements array - remove undefined entries\n if (\n this.parsedMesh.boundaryElements.length > 0 &&\n this.parsedMesh.boundaryElements[0] === undefined\n ) {\n const fixedBoundaryElements = [];\n for (let i = 1; i < this.parsedMesh.boundaryElements.length; i++) {\n if (this.parsedMesh.boundaryElements[i]) {\n fixedBoundaryElements.push(this.parsedMesh.boundaryElements[i]);\n }\n }\n this.parsedMesh.boundaryElements = fixedBoundaryElements;\n }\n }\n }\n }\n\n return this.parsedMesh;\n }\n}\n\nexport class Mesh1D extends Mesh {\n /**\n * Constructor to initialize the 1D mesh\n * @param {object} config - Configuration object for the 1D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({ numElementsX = null, maxX = null, elementOrder = \"linear\", parsedMesh = null }) {\n super({\n numElementsX,\n maxX,\n numElementsY: 1,\n maxY: 0,\n meshDimension: \"1D\",\n elementOrder,\n parsedMesh,\n });\n\n if (this.numElementsX === null || this.maxX === null) {\n errorLog(\"numElementsX and maxX are required parameters when generating a 1D mesh from geometry\");\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n let totalNodesX, deltaX;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX;\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n\n nodesXCoordinates[0] = xStart;\n for (let nodeIndex = 1; nodeIndex < totalNodesX; nodeIndex++) {\n nodesXCoordinates[nodeIndex] = nodesXCoordinates[nodeIndex - 1] + deltaX / 2;\n }\n }\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder);\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n\n // Return x coordinates of nodes, total nodes, NOP array, and boundary elements\n return {\n nodesXCoordinates,\n totalNodesX,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) {\n // TODO: The totalNodesX is not used in the original function. Verify if\n // there is a multiple calculation on the totalNodes.\n\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear 1D elements with the following nodes representation:\n *\n * 1 --- 2\n *\n */\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 2; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic 1D elements with the following nodes representation:\n *\n * 1--2--3\n *\n */\n let columnCounter = 0;\n for (let elementIndex = 0; elementIndex < numElementsX; elementIndex++) {\n nop[elementIndex] = [];\n for (let nodeIndex = 1; nodeIndex <= 3; nodeIndex++) {\n nop[elementIndex][nodeIndex - 1] = elementIndex + nodeIndex + columnCounter;\n }\n columnCounter += 1;\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 1D domains (line segments):\n * 0 - Left node of reference element (maps to physical left endpoint)\n * 1 - Right node of reference element (maps to physical right endpoint)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 2; // For 1D, we only have two sides (left and right)\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // Left boundary (element 0, side 0)\n boundaryElements[0].push([0, 0]);\n\n // Right boundary (last element, side 1)\n boundaryElements[1].push([this.numElementsX - 1, 1]);\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n\nexport class Mesh2D extends Mesh {\n /**\n * Constructor to initialize the 2D mesh\n * @param {object} config - Configuration object for the 2D mesh\n * @param {number} [config.numElementsX] - Number of elements along the x-axis (required for geometry-based mesh)\n * @param {number} [config.maxX] - Maximum x-coordinate of the mesh (required for geometry-based mesh)\n * @param {number} [config.numElementsY] - Number of elements along the y-axis (required for geometry-based mesh)\n * @param {number} [config.maxY] - Maximum y-coordinate of the mesh (required for geometry-based mesh)\n * @param {string} [config.elementOrder='linear'] - The order of elements, either 'linear' or 'quadratic'\n * @param {object} [config.parsedMesh=null] - Optional pre-parsed mesh data\n */\n constructor({\n numElementsX = null,\n maxX = null,\n numElementsY = null,\n maxY = null,\n elementOrder = \"linear\",\n parsedMesh = null,\n }) {\n super({\n numElementsX,\n maxX,\n numElementsY,\n maxY,\n meshDimension: \"2D\",\n elementOrder,\n parsedMesh,\n });\n\n // Validate geometry parameters (when not using a parsed mesh)\n if (\n !parsedMesh &&\n (this.numElementsX === null || this.maxX === null || this.numElementsY === null || this.maxY === null)\n ) {\n errorLog(\n \"numElementsX, maxX, numElementsY, and maxY are required parameters when generating a 2D mesh from geometry\"\n );\n }\n }\n\n generateMesh() {\n let nodesXCoordinates = [];\n let nodesYCoordinates = [];\n const xStart = 0;\n const yStart = 0;\n let totalNodesX, totalNodesY, deltaX, deltaY;\n\n if (this.elementOrder === \"linear\") {\n totalNodesX = this.numElementsX + 1;\n totalNodesY = this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + nodeIndexY * deltaY;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + nodeIndexX * deltaX;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + nodeIndexY * deltaY;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n totalNodesX = 2 * this.numElementsX + 1;\n totalNodesY = 2 * this.numElementsY + 1;\n deltaX = (this.maxX - xStart) / this.numElementsX;\n deltaY = (this.maxY - yStart) / this.numElementsY;\n\n nodesXCoordinates[0] = xStart;\n nodesYCoordinates[0] = yStart;\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nodeIndexY] = nodesXCoordinates[0];\n nodesYCoordinates[nodeIndexY] = nodesYCoordinates[0] + (nodeIndexY * deltaY) / 2;\n }\n for (let nodeIndexX = 1; nodeIndexX < totalNodesX; nodeIndexX++) {\n const nnode = nodeIndexX * totalNodesY;\n nodesXCoordinates[nnode] = nodesXCoordinates[0] + (nodeIndexX * deltaX) / 2;\n nodesYCoordinates[nnode] = nodesYCoordinates[0];\n for (let nodeIndexY = 1; nodeIndexY < totalNodesY; nodeIndexY++) {\n nodesXCoordinates[nnode + nodeIndexY] = nodesXCoordinates[nnode];\n nodesYCoordinates[nnode + nodeIndexY] = nodesYCoordinates[nnode] + (nodeIndexY * deltaY) / 2;\n }\n }\n }\n\n // Generate nodal numbering (NOP) array\n const nodalNumbering = this.generate2DNodalNumbering(\n this.numElementsX,\n this.numElementsY,\n totalNodesY,\n this.elementOrder\n );\n\n // Find boundary elements\n const boundaryElements = this.findBoundaryElements();\n\n debugLog(\"Generated node X coordinates: \" + JSON.stringify(nodesXCoordinates));\n debugLog(\"Generated node Y coordinates: \" + JSON.stringify(nodesYCoordinates));\n\n // Return statement\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nodalNumbering,\n boundaryElements,\n };\n }\n\n /**\n * Function to generate the nodal numbering (NOP) array for a structured mesh\n * This array represents the connectivity between elements and their corresponding nodes\n * @param {number} numElementsX - Number of elements along the x-axis\n * @param {number} [numElementsY] - Number of elements along the y-axis (optional for 1D)\n * @param {number} totalNodesX - Total number of nodes along the x-axis\n * @param {number} [totalNodesY] - Total number of nodes along the y-axis (optional for 1D)\n * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic'\n * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh\n */\n generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) {\n let elementIndex = 0;\n let nop = [];\n\n if (elementOrder === \"linear\") {\n /**\n * Linear rectangular elements with the following nodes representation:\n *\n * 1 --- 3\n * | |\n * 0 --- 2\n *\n */\n let rowCounter = 0;\n let columnCounter = 2;\n for (let elementIndex = 0; elementIndex < numElementsX * numElementsY; elementIndex++) {\n rowCounter += 1;\n nop[elementIndex] = [];\n nop[elementIndex][0] = elementIndex + columnCounter - 1;\n nop[elementIndex][1] = elementIndex + columnCounter;\n nop[elementIndex][2] = elementIndex + columnCounter + numElementsY;\n nop[elementIndex][3] = elementIndex + columnCounter + numElementsY + 1;\n if (rowCounter === numElementsY) {\n columnCounter += 1;\n rowCounter = 0;\n }\n }\n } else if (elementOrder === \"quadratic\") {\n /**\n * Quadratic rectangular elements with the following nodes representation:\n *\n * 2--5--8\n * | |\n * 1 4 7\n * | |\n * 0--3--6\n *\n */\n for (let elementIndexX = 1; elementIndexX <= numElementsX; elementIndexX++) {\n for (let elementIndexY = 1; elementIndexY <= numElementsY; elementIndexY++) {\n nop[elementIndex] = [];\n for (let nodeIndex1 = 1; nodeIndex1 <= 3; nodeIndex1++) {\n let nodeIndex2 = 3 * nodeIndex1 - 2;\n nop[elementIndex][nodeIndex2 - 1] =\n totalNodesY * (2 * elementIndexX + nodeIndex1 - 3) + 2 * elementIndexY - 1;\n nop[elementIndex][nodeIndex2] = nop[elementIndex][nodeIndex2 - 1] + 1;\n nop[elementIndex][nodeIndex2 + 1] = nop[elementIndex][nodeIndex2 - 1] + 2;\n }\n elementIndex = elementIndex + 1;\n }\n }\n }\n\n return nop;\n }\n\n /**\n * Function to find the elements that belong to each boundary of a domain\n * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary\n * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side\n * of the reference element is in contact with the physical boundary:\n *\n * For 2D domains (rectangular):\n * 0 - Bottom side of reference element (maps to physical bottom boundary)\n * 1 - Left side of reference element (maps to physical left boundary)\n * 2 - Top side of reference element (maps to physical top boundary)\n * 3 - Right side of reference element (maps to physical right boundary)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top)\n\n for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) {\n boundaryElements.push([]);\n }\n\n // TODO: Why to loop through all elements? Is it not better to loop over only the\n // elements that are on the boundary? eg: [0, this.numElementsX - 1] on x and\n // [0, this.numElementsY - 1] on y\n for (let elementIndexX = 0; elementIndexX < this.numElementsX; elementIndexX++) {\n for (let elementIndexY = 0; elementIndexY < this.numElementsY; elementIndexY++) {\n const elementIndex = elementIndexX * this.numElementsY + elementIndexY;\n\n // Bottom boundary\n if (elementIndexY === 0) {\n boundaryElements[0].push([elementIndex, 0]);\n }\n\n // Left boundary\n if (elementIndexX === 0) {\n boundaryElements[1].push([elementIndex, 1]);\n }\n\n // Top boundary\n if (elementIndexY === this.numElementsY - 1) {\n boundaryElements[2].push([elementIndex, 2]);\n }\n\n // Right boundary\n if (elementIndexX === this.numElementsX - 1) {\n boundaryElements[3].push([elementIndex, 3]);\n }\n }\n }\n\n debugLog(\"Identified boundary elements by side: \" + JSON.stringify(boundaryElements));\n this.boundaryElementsProcessed = true;\n return boundaryElements;\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Class to handle numerical integration using Gauss quadrature\n */\nexport class NumericalIntegration {\n /**\n * Constructor to initialize the NumericalIntegration class\n * @param {string} meshDimension - The dimension of the mesh\n * @param {string} elementOrder - The order of elements\n */\n constructor({ meshDimension, elementOrder }) {\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to return Gauss points and weights based on element configuration\n * @returns {object} An object containing:\n * - gaussPoints: Array of Gauss points\n * - gaussWeights: Array of Gauss weights\n */\n getGaussPointsAndWeights() {\n let gaussPoints = []; // Gauss points\n let gaussWeights = []; // Gauss weights\n\n if (this.elementOrder === \"linear\") {\n // For linear elements, use 1-point Gauss quadrature\n gaussPoints[0] = 0.5;\n gaussWeights[0] = 1;\n } else if (this.elementOrder === \"quadratic\") {\n // For quadratic elements, use 3-point Gauss quadrature\n gaussPoints[0] = (1 - Math.sqrt(3 / 5)) / 2;\n gaussPoints[1] = 0.5;\n gaussPoints[2] = (1 + Math.sqrt(3 / 5)) / 2;\n gaussWeights[0] = 5 / 18;\n gaussWeights[1] = 8 / 18;\n gaussWeights[2] = 5 / 18;\n }\n\n return { gaussPoints, gaussWeights };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nimport { BasisFunctions } from \"./basisFunctionsScript.js\";\nimport { Mesh1D, Mesh2D } from \"./meshGenerationScript.js\";\nimport { NumericalIntegration } from \"../methods/numericalIntegrationScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to prepare the mesh for finite element analysis\n * @param {object} meshConfig - Object containing computational mesh details\n * @returns {object} An object containing all mesh-related data\n */\nexport function prepareMesh(meshConfig) {\n const { meshDimension, numElementsX, numElementsY, maxX, maxY, elementOrder, parsedMesh } = meshConfig;\n\n // Create a new instance of the Mesh class\n let mesh;\n if (meshDimension === \"1D\") {\n mesh = new Mesh1D({ numElementsX, maxX, elementOrder, parsedMesh });\n } else if (meshDimension === \"2D\") {\n mesh = new Mesh2D({ numElementsX, maxX, numElementsY, maxY, elementOrder, parsedMesh });\n } else {\n errorLog(\"Mesh dimension must be either '1D' or '2D'.\");\n }\n\n // Use the parsed mesh in case it was already passed with Gmsh format\n const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh();\n\n // Extract nodes coordinates and nodal numbering (NOP) from the mesh data\n let nodesXCoordinates = nodesCoordinatesAndNumbering.nodesXCoordinates;\n let nodesYCoordinates = nodesCoordinatesAndNumbering.nodesYCoordinates;\n let totalNodesX = nodesCoordinatesAndNumbering.totalNodesX;\n let totalNodesY = nodesCoordinatesAndNumbering.totalNodesY;\n let nop = nodesCoordinatesAndNumbering.nodalNumbering;\n let boundaryElements = nodesCoordinatesAndNumbering.boundaryElements;\n\n // Check the mesh type\n const isParsedMesh = parsedMesh !== undefined && parsedMesh !== null;\n\n // Calculate totalElements and totalNodes based on mesh type\n let totalElements, totalNodes;\n\n if (isParsedMesh) {\n totalElements = nop.length; // Number of elements is the length of the nodal numbering array\n totalNodes = nodesXCoordinates.length; // Number of nodes is the length of the coordinates array\n debugLog(`Using parsed mesh with ${totalElements} elements and ${totalNodes} nodes`);\n } else {\n // For structured mesh, calculate based on dimensions\n totalElements = numElementsX * (meshDimension === \"2D\" ? numElementsY : 1);\n totalNodes = totalNodesX * (meshDimension === \"2D\" ? totalNodesY : 1);\n debugLog(`Using mesh generated from geometry with ${totalElements} elements and ${totalNodes} nodes`);\n }\n\n return {\n nodesXCoordinates,\n nodesYCoordinates,\n totalNodesX,\n totalNodesY,\n nop,\n boundaryElements,\n totalElements,\n totalNodes,\n meshDimension,\n elementOrder,\n };\n}\n\n/**\n * Function to initialize the FEA matrices and numerical tools\n * @param {object} meshData - Object containing mesh data from prepareMesh()\n * @returns {object} An object containing initialized matrices and numerical tools\n */\nexport function initializeFEA(meshData) {\n const { totalNodes, nop, meshDimension, elementOrder } = meshData;\n\n // Initialize variables for matrix assembly\n let residualVector = [];\n let jacobianMatrix = [];\n let localToGlobalMap = [];\n\n // Initialize jacobianMatrix and residualVector arrays\n for (let nodeIndex = 0; nodeIndex < totalNodes; nodeIndex++) {\n residualVector[nodeIndex] = 0;\n jacobianMatrix.push([]);\n for (let colIndex = 0; colIndex < totalNodes; colIndex++) {\n jacobianMatrix[nodeIndex][colIndex] = 0;\n }\n }\n\n // Initialize the BasisFunctions class\n const basisFunctions = new BasisFunctions({\n meshDimension,\n elementOrder,\n });\n\n // Initialize the NumericalIntegration class\n const numericalIntegration = new NumericalIntegration({\n meshDimension,\n elementOrder,\n });\n\n // Calculate Gauss points and weights\n let gaussPointsAndWeights = numericalIntegration.getGaussPointsAndWeights();\n let gaussPoints = gaussPointsAndWeights.gaussPoints;\n let gaussWeights = gaussPointsAndWeights.gaussWeights;\n\n // Determine the number of nodes in the reference element based on the first element in the nop array\n const numNodes = nop[0].length;\n\n return {\n residualVector,\n jacobianMatrix,\n localToGlobalMap,\n basisFunctions,\n gaussPoints,\n gaussWeights,\n numNodes,\n };\n}\n\n/**\n * Function to perform isoparametric mapping for 1D elements\n * @param {object} params - Parameters for the mapping\n * @returns {object} An object containing the mapped data\n */\nexport function performIsoparametricMapping1D(params) {\n const { basisFunction, basisFunctionDerivKsi, nodesXCoordinates, localToGlobalMap, numNodes } = params;\n\n let xCoordinates = 0;\n let ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n }\n let detJacobian = ksiDerivX;\n\n // Compute x-derivative of basis functions\n let basisFunctionDerivX = [];\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian;\n }\n\n return {\n xCoordinates,\n detJacobian,\n basisFunctionDerivX,\n };\n}\n\n/**\n * Function to perform isoparametric mapping for 2D elements\n * @param {object} params - Parameters for the mapping\n * @returns {object} An object containing the mapped data\n */\nexport function performIsoparametricMapping2D(params) {\n const {\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n } = params;\n\n let xCoordinates = 0;\n let yCoordinates = 0;\n let ksiDerivX = 0;\n let etaDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivY = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n yCoordinates += nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex];\n ksiDerivX += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivX += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n ksiDerivY += nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex];\n etaDerivY += nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivEta[localNodeIndex];\n }\n let detJacobian = ksiDerivX * etaDerivY - etaDerivX * ksiDerivY;\n\n // Compute x-derivative and y-derivative of basis functions\n let basisFunctionDerivX = [];\n let basisFunctionDerivY = [];\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // The x-derivative of the n basis function\n basisFunctionDerivX[localNodeIndex] =\n (etaDerivY * basisFunctionDerivKsi[localNodeIndex] -\n ksiDerivY * basisFunctionDerivEta[localNodeIndex]) /\n detJacobian;\n // The y-derivative of the n basis function\n basisFunctionDerivY[localNodeIndex] =\n (ksiDerivX * basisFunctionDerivEta[localNodeIndex] -\n etaDerivX * basisFunctionDerivKsi[localNodeIndex]) /\n detJacobian;\n }\n\n return {\n xCoordinates,\n yCoordinates,\n detJacobian,\n basisFunctionDerivX,\n basisFunctionDerivY,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// This class is essentially the same with ThermalBoundaryConditions\n// Need to consolidate them in the future\n\n/**\n * Class to handle generic boundary conditions application\n */\nexport class GenericBoundaryConditions {\n /**\n * Constructor to initialize the GenericBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant value boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant value boundary conditions\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantValue\") {\n const value = this.boundaryConditions[boundaryKey][1];\n debugLog(`Boundary ${boundaryKey}: Applying constant value of ${value} (Dirichlet condition)`);\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant value to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the constantValue\n residualVector[globalNodeIndex] = value;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport {\n initializeFEA,\n performIsoparametricMapping1D,\n performIsoparametricMapping2D,\n} from \"../mesh/meshUtilsScript.js\";\nimport { basicLog, debugLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the Jacobian matrix and residuals vector for the front propagation model\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} solutionVector - The solution vector for non-linear equations\n * @param {number} eikonalActivationFlag - Activation parameter for the eikonal equation\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n */\nexport function assembleFrontPropagationMat(\n meshData,\n boundaryConditions,\n solutionVector,\n eikonalActivationFlag\n) {\n basicLog(\"Starting front propagation matrix assembly...\");\n\n // Calculate eikonal viscous term\n const baseEikonalViscousTerm = 1e-2; // Base viscous term that remains when eikonal equation is fully activated\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n basicLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n basicLog(`eikonalActivationFlag: ${eikonalActivationFlag}`);\n\n // Extract mesh data\n const {\n nodesXCoordinates,\n nodesYCoordinates,\n nop,\n boundaryElements,\n totalElements,\n meshDimension,\n elementOrder,\n } = meshData;\n\n // Initialize FEA components\n const FEAData = initializeFEA(meshData);\n const {\n residualVector,\n jacobianMatrix,\n localToGlobalMap,\n basisFunctions,\n gaussPoints,\n gaussWeights,\n numNodes,\n } = FEAData;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n // Map local element nodes to global mesh nodes\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D front propagation (eikonal) equation\n if (meshDimension === \"1D\") {\n // Get basis functions for the current Gauss point\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n\n // Perform isoparametric mapping\n const mappingResult = performIsoparametricMapping1D({\n basisFunction: basisFunctionsAndDerivatives.basisFunction,\n basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Extract mapping results\n const { detJacobian, basisFunctionDerivX } = mappingResult;\n const basisFunction = basisFunctionsAndDerivatives.basisFunction;\n\n // Calculate solution derivative\n let solutionDerivX = 0;\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // To perform residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // To perform jacobianMatrix calculation here\n }\n }\n }\n // 2D front propagation (eikonal) equation\n else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Get basis functions for the current Gauss point\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n\n // Perform isoparametric mapping\n const mappingResult = performIsoparametricMapping2D({\n basisFunction: basisFunctionsAndDerivatives.basisFunction,\n basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi,\n basisFunctionDerivEta: basisFunctionsAndDerivatives.basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Extract mapping results\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = mappingResult;\n const basisFunction = basisFunctionsAndDerivatives.basisFunction;\n\n // Calculate solution derivatives\n let solutionDerivX = 0;\n let solutionDerivY = 0;\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n solutionDerivX +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex];\n solutionDerivY +=\n solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivY[localNodeIndex];\n }\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n\n // residualVector: Viscous term contribution (to stabilize the solution)\n residualVector[localToGlobalMap1] +=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivX[localNodeIndex1] *\n solutionDerivX +\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunctionDerivY[localNodeIndex1] *\n solutionDerivY;\n\n // residualVector: Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n residualVector[localToGlobalMap1] +=\n eikonalActivationFlag *\n (gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1] *\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2) -\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n basisFunction[localNodeIndex1]);\n }\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n\n // jacobianMatrix: Viscous term contribution\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n\n // jacobianMatrix: Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n eikonalActivationFlag *\n (-(\n detJacobian *\n solutionDerivX *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]\n ) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivX[localNodeIndex2] -\n ((detJacobian *\n solutionDerivY *\n basisFunction[localNodeIndex1] *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2]) /\n Math.sqrt(solutionDerivX ** 2 + solutionDerivY ** 2 + 1e-8)) *\n basisFunctionDerivY[localNodeIndex2];\n }\n }\n }\n }\n }\n }\n }\n\n // Apply boundary conditions\n basicLog(\"Applying generic boundary conditions...\");\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose ConstantValue boundary conditions\n genericBoundaryConditions.imposeConstantValueBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant value boundary conditions applied\");\n\n // Print all residuals in debug mode\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to handle thermal boundary conditions application\n */\nexport class ThermalBoundaryConditions {\n /**\n * Constructor to initialize the ThermalBoundaryConditions class\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @param {array} boundaryElements - Array containing elements that belong to each boundary\n * @param {array} nop - Nodal numbering (NOP) array representing the connectivity between elements and nodes\n * @param {string} meshDimension - The dimension of the mesh (e.g., \"2D\")\n * @param {string} elementOrder - The order of elements (e.g., \"linear\", \"quadratic\")\n */\n constructor(boundaryConditions, boundaryElements, nop, meshDimension, elementOrder) {\n this.boundaryConditions = boundaryConditions;\n this.boundaryElements = boundaryElements;\n this.nop = nop;\n this.meshDimension = meshDimension;\n this.elementOrder = elementOrder;\n }\n\n /**\n * Function to impose constant temperature boundary conditions (Dirichlet type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\n basicLog(\"Applying constant temperature boundary conditions\");\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 1: [1], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0], // Node at the left side of the reference element\n 2: [2], // Node at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"constantTemp\") {\n const tempValue = this.boundaryConditions[boundaryKey][1];\n debugLog(\n `Boundary ${boundaryKey}: Applying constant temperature of ${tempValue} K (Dirichlet condition)`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n const boundarySides = {\n 0: [0, 2], // Nodes at the bottom side of the reference element\n 1: [0, 1], // Nodes at the left side of the reference element\n 2: [1, 3], // Nodes at the top side of the reference element\n 3: [2, 3], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n } else if (this.elementOrder === \"quadratic\") {\n const boundarySides = {\n 0: [0, 3, 6], // Nodes at the bottom side of the reference element\n 1: [0, 1, 2], // Nodes at the left side of the reference element\n 2: [2, 5, 8], // Nodes at the top side of the reference element\n 3: [6, 7, 8], // Nodes at the right side of the reference element\n };\n boundarySides[side].forEach((nodeIndex) => {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied constant temperature to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n // Set the residual vector to the ConstantTemp value\n residualVector[globalNodeIndex] = tempValue;\n // Set the Jacobian matrix row to zero\n for (let colIndex = 0; colIndex < residualVector.length; colIndex++) {\n jacobianMatrix[globalNodeIndex][colIndex] = 0;\n }\n // Set the diagonal entry of the Jacobian matrix to one\n jacobianMatrix[globalNodeIndex][globalNodeIndex] = 1;\n });\n }\n });\n }\n });\n }\n }\n\n /**\n * Function to impose convection boundary conditions (Robin type)\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n */\n imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n ) {\n basicLog(\"Applying convection boundary conditions\");\n // Extract convection parameters from boundary conditions\n let convectionHeatTranfCoeff = [];\n let convectionExtTemp = [];\n Object.keys(this.boundaryConditions).forEach((key) => {\n const boundaryCondition = this.boundaryConditions[key];\n if (boundaryCondition[0] === \"convection\") {\n convectionHeatTranfCoeff[key] = boundaryCondition[1];\n convectionExtTemp[key] = boundaryCondition[2];\n }\n });\n\n if (this.meshDimension === \"1D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 1;\n }\n } else if (this.elementOrder === \"quadratic\") {\n if (side === 0) {\n // Node at the left side of the reference element\n nodeIndex = 0;\n } else {\n // Node at the right side of the reference element\n nodeIndex = 2;\n }\n }\n\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n residualVector[globalNodeIndex] += -convectionCoeff * extTemp;\n jacobianMatrix[globalNodeIndex][globalNodeIndex] += convectionCoeff;\n });\n }\n });\n } else if (this.meshDimension === \"2D\") {\n Object.keys(this.boundaryConditions).forEach((boundaryKey) => {\n if (this.boundaryConditions[boundaryKey][0] === \"convection\") {\n const convectionCoeff = convectionHeatTranfCoeff[boundaryKey];\n const extTemp = convectionExtTemp[boundaryKey];\n debugLog(\n `Boundary ${boundaryKey}: Applying convection with heat transfer coefficient h=${convectionCoeff} W/(m²·K) and external temperature T∞=${extTemp} K`\n );\n this.boundaryElements[boundaryKey].forEach(([elementIndex, side]) => {\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 2;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 0;\n lastNodeIndex = 2;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[0];\n gaussPoint2 = 1;\n firstNodeIndex = 1;\n lastNodeIndex = 4;\n nodeIncrement = 2;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[0];\n firstNodeIndex = 2;\n lastNodeIndex = 4;\n nodeIncrement = 1;\n }\n\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n if (side === 0) {\n // Nodes at the bottom side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 0;\n firstNodeIndex = 0;\n lastNodeIndex = 7;\n nodeIncrement = 3;\n } else if (side === 1) {\n // Nodes at the left side of the reference element\n gaussPoint1 = 0;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 0;\n lastNodeIndex = 3;\n nodeIncrement = 1;\n } else if (side === 2) {\n // Nodes at the top side of the reference element\n gaussPoint1 = gaussPoints[gaussPointIndex];\n gaussPoint2 = 1;\n firstNodeIndex = 2;\n lastNodeIndex = 9;\n nodeIncrement = 3;\n } else if (side === 3) {\n // Nodes at the right side of the reference element\n gaussPoint1 = 1;\n gaussPoint2 = gaussPoints[gaussPointIndex];\n firstNodeIndex = 6;\n lastNodeIndex = 9;\n nodeIncrement = 1;\n }\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n let basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n let basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n let ksiDerivX = 0;\n let ksiDerivY = 0;\n let etaDerivX = 0;\n let etaDerivY = 0;\n const numNodes = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n // For boundaries along Ksi (horizontal), use Ksi derivatives\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n }\n // For boundaries along Eta (vertical), use Eta derivatives\n else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute the length of tangent vector\n let tangentVectorLength;\n if (side === 0 || side === 2) {\n tangentVectorLength = Math.sqrt(ksiDerivX ** 2 + ksiDerivY ** 2);\n } else {\n tangentVectorLength = Math.sqrt(etaDerivX ** 2 + etaDerivY ** 2);\n }\n\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n let globalNodeIndex = this.nop[elementIndex][localNodeIndex] - 1;\n debugLog(\n ` - Applied convection boundary condition to node ${globalNodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${localNodeIndex + 1})`\n );\n\n // Apply boundary condition with proper Jacobian for all sides\n residualVector[globalNodeIndex] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n convectionCoeff *\n extTemp;\n\n for (\n let localNodeIndex2 = firstNodeIndex;\n localNodeIndex2 < lastNodeIndex;\n localNodeIndex2 += nodeIncrement\n ) {\n let globalNodeIndex2 = this.nop[elementIndex][localNodeIndex2] - 1;\n jacobianMatrix[globalNodeIndex][globalNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n });\n }\n });\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { assembleSolidHeatTransferFront } from \"../solvers/solidHeatTransferScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// Add an exported wrapper to obtain results for plotting\nexport function runFrontalSolver(meshConfig, boundaryConditions) {\n main(meshConfig, boundaryConditions);\n return {\n solutionVector: block1.u.slice(0, block1.np),\n nodesCoordinates: {\n nodesXCoordinates: block1.xpt.slice(0, block1.np),\n nodesYCoordinates: block1.ypt.slice(0, block1.np),\n },\n };\n}\n\n// Constants\nconst nemax = 1600;\nconst nnmax = 6724;\nconst nmax = 2000;\n\n// Common block equivalents as objects\nconst block1 = {\n nex: 0,\n ney: 0,\n nnx: 0,\n nny: 0,\n ne: 0,\n np: 0,\n xorigin: 0,\n yorigin: 0,\n xlast: 0,\n ylast: 0,\n deltax: 0,\n deltay: 0,\n nop: Array(nemax)\n .fill()\n .map(() => Array(9).fill(0)),\n xpt: Array(nnmax).fill(0),\n ypt: Array(nnmax).fill(0),\n ncod: Array(nnmax).fill(0),\n bc: Array(nnmax).fill(0),\n r1: Array(nnmax).fill(0),\n u: Array(nnmax).fill(0),\n ntop: Array(nemax).fill(0),\n nlat: Array(nemax).fill(0),\n};\n\nconst gauss = {\n w: [0.27777777777778, 0.444444444444, 0.27777777777778],\n gp: [0.1127016654, 0.5, 0.8872983346],\n};\n\nconst fro1 = {\n iwr1: 0,\n npt: 0,\n ntra: 0,\n nbn: Array(nemax).fill(0),\n det: 1,\n sk: Array(nmax * nmax).fill(0),\n ice1: 0,\n};\n\nconst fabf1 = {\n estifm: Array(9)\n .fill()\n .map(() => Array(9).fill(0)),\n nell: 0,\n};\n\nconst fb1 = {\n ecv: Array(2000000).fill(0),\n lhed: Array(nmax).fill(0),\n qq: Array(nmax).fill(0),\n ecpiv: Array(2000000).fill(0),\n};\n\n// Instantiate shared basis functions handler (biquadratic 2D)\nconst basisFunctionsLib = new BasisFunctions({ meshDimension: \"2D\", elementOrder: \"quadratic\" });\n\n// Main program logic\nfunction main(meshConfig, boundaryConditions) {\n // console.log(\"2-D problem. Biquadratic basis functions\\n\");\n\n xydiscr(meshConfig);\n nodnumb();\n xycoord();\n // console.log(`nex=${block1.nex} ney=${block1.ney} ne=${block1.ne} np=${block1.np}\\n`);\n\n // Initialize all nodes with no boundary condition\n for (let i = 0; i < block1.np; i++) {\n block1.ncod[i] = 0;\n block1.bc[i] = 0;\n }\n\n // Apply boundary conditions based on the boundaryConditions parameter\n Object.keys(boundaryConditions).forEach((boundaryKey) => {\n const condition = boundaryConditions[boundaryKey];\n\n // Handle constantTemp (Dirichlet) boundary conditions\n if (condition[0] === \"constantTemp\") {\n const tempValue = boundaryConditions[boundaryKey][1];\n\n // Apply boundary condition to the appropriate nodes based on boundary key\n switch (boundaryKey) {\n case \"0\": // Bottom boundary (y = yorigin)\n for (let col = 0; col < block1.nnx; col++) {\n const nodeIndex = col * block1.nny;\n block1.ncod[nodeIndex] = 1;\n block1.bc[nodeIndex] = tempValue;\n }\n break;\n\n case \"1\": // Right boundary (x = xlast)\n for (let j = 0; j < block1.nny; j++) {\n block1.ncod[j] = 1;\n block1.bc[j] = tempValue;\n }\n break;\n\n case \"2\": // Top boundary (y = ylast)\n for (let col = 0; col < block1.nnx; col++) {\n const nodeIndex = col * block1.nny + (block1.nny - 1);\n block1.ncod[nodeIndex] = 1;\n block1.bc[nodeIndex] = tempValue;\n }\n break;\n\n case \"3\": // Left boundary (x = xorigin)\n for (let j = 0; j < block1.nny; j++) {\n const nodeIndex = (block1.nnx - 1) * block1.nny + j;\n block1.ncod[nodeIndex] = 1;\n block1.bc[nodeIndex] = tempValue;\n }\n break;\n }\n }\n // Other boundary condition types can be handled later if needed\n });\n\n // Prepare natural boundary conditions\n for (let i = 0; i < block1.ne; i++) {\n block1.ntop[i] = 0;\n block1.nlat[i] = 0;\n }\n\n // for (let i = block1.ney - 1; i < block1.ne; i += block1.ney) {\n // block1.ntop[i] = 1;\n // }\n\n // for (let i = block1.ne - block1.ney; i < block1.ne; i++) {\n // block1.nlat[i] = 1;\n // }\n\n // Initialization\n for (let i = 0; i < block1.np; i++) {\n block1.r1[i] = 0;\n }\n\n fro1.npt = block1.np;\n fro1.iwr1 = 0;\n fro1.ntra = 1;\n fro1.det = 1;\n\n for (let i = 0; i < block1.ne; i++) {\n fro1.nbn[i] = 9;\n }\n\n front();\n\n // Copy solution\n for (let i = 0; i < block1.np; i++) {\n block1.u[i] = fro1.sk[i];\n }\n\n // Output results to console\n for (let i = 0; i < block1.np; i++) {\n debugLog(\n `${block1.xpt[i].toExponential(5)} ${block1.ypt[i].toExponential(5)} ${block1.u[i].toExponential(5)}`\n );\n }\n}\n\n// Discretization\nfunction xydiscr(meshConfig) {\n // Extract values from meshConfig\n const { meshDimension, numElementsX, numElementsY, maxX, maxY, elementOrder, parsedMesh } = meshConfig;\n\n block1.nex = numElementsX;\n block1.ney = numElementsY;\n block1.xorigin = 0;\n block1.yorigin = 0;\n block1.xlast = maxX;\n block1.ylast = maxY;\n block1.deltax = (block1.xlast - block1.xorigin) / block1.nex;\n block1.deltay = (block1.ylast - block1.yorigin) / block1.ney;\n}\n\n// Nodal numbering\nfunction nodnumb() {\n block1.ne = block1.nex * block1.ney;\n block1.nnx = 2 * block1.nex + 1;\n block1.nny = 2 * block1.ney + 1;\n block1.np = block1.nnx * block1.nny;\n\n let nel = 0;\n for (let i = 1; i <= block1.nex; i++) {\n for (let j = 1; j <= block1.ney; j++) {\n nel++;\n for (let k = 1; k <= 3; k++) {\n let l = 3 * k - 2;\n block1.nop[nel - 1][l - 1] = block1.nny * (2 * i + k - 3) + 2 * j - 1;\n block1.nop[nel - 1][l] = block1.nop[nel - 1][l - 1] + 1;\n block1.nop[nel - 1][l + 1] = block1.nop[nel - 1][l - 1] + 2;\n }\n }\n }\n}\n\n// Coordinate setup\nfunction xycoord() {\n block1.xpt[0] = block1.xorigin;\n block1.ypt[0] = block1.yorigin;\n\n for (let i = 1; i <= block1.nnx; i++) {\n let nnode = (i - 1) * block1.nny;\n block1.xpt[nnode] = block1.xpt[0] + ((i - 1) * block1.deltax) / 2;\n block1.ypt[nnode] = block1.ypt[0];\n\n for (let j = 2; j <= block1.nny; j++) {\n block1.xpt[nnode + j - 1] = block1.xpt[nnode];\n block1.ypt[nnode + j - 1] = block1.ypt[nnode] + ((j - 1) * block1.deltay) / 2;\n }\n }\n}\n\n// Element stiffness matrix and residuals (delegated to external assembly function)\nfunction abfind() {\n const elementIndex = fabf1.nell - 1;\n\n const { estifm, localLoad, ngl } = assembleSolidHeatTransferFront({\n elementIndex,\n nop: block1.nop,\n xCoordinates: block1.xpt,\n yCoordinates: block1.ypt,\n basisFunctions: basisFunctionsLib,\n gaussPoints: gauss.gp,\n gaussWeights: gauss.w,\n ntopFlag: block1.ntop[elementIndex] === 1,\n nlatFlag: block1.nlat[elementIndex] === 1,\n });\n\n // Copy element matrix\n for (let i = 0; i < 9; i++) {\n for (let j = 0; j < 9; j++) {\n fabf1.estifm[i][j] = estifm[i][j];\n }\n }\n\n // Accumulate local load into global RHS\n for (let a = 0; a < 9; a++) {\n const g = ngl[a] - 1;\n block1.r1[g] += localLoad[a];\n }\n}\n\n// Frontal solver\nfunction front() {\n let ldest = Array(9).fill(0);\n let kdest = Array(9).fill(0);\n let khed = Array(nmax).fill(0);\n let kpiv = Array(nmax).fill(0);\n let lpiv = Array(nmax).fill(0);\n let jmod = Array(nmax).fill(0);\n let pvkol = Array(nmax).fill(0);\n let eq = Array(nmax)\n .fill()\n .map(() => Array(nmax).fill(0));\n let nrs = Array(nnmax).fill(0);\n let ncs = Array(nnmax).fill(0);\n let check = Array(nnmax).fill(0);\n let lco; // Declare lco once at function scope\n\n let ice = 1;\n fro1.iwr1++;\n let ipiv = 1;\n let nsum = 1;\n fabf1.nell = 0;\n\n for (let i = 0; i < fro1.npt; i++) {\n nrs[i] = 0;\n ncs[i] = 0;\n }\n\n if (fro1.ntra !== 0) {\n // Prefront: find last appearance of each node\n for (let i = 0; i < fro1.npt; i++) {\n check[i] = 0;\n }\n\n for (let i = 0; i < block1.ne; i++) {\n let nep = block1.ne - i - 1;\n for (let j = 0; j < fro1.nbn[nep]; j++) {\n let k = block1.nop[nep][j];\n if (check[k - 1] === 0) {\n check[k - 1] = 1;\n block1.nop[nep][j] = -block1.nop[nep][j];\n }\n }\n }\n }\n\n fro1.ntra = 0;\n let lcol = 0;\n let krow = 0;\n\n for (let i = 0; i < nmax; i++) {\n for (let j = 0; j < nmax; j++) {\n eq[j][i] = 0;\n }\n }\n\n while (true) {\n fabf1.nell++;\n abfind();\n\n let n = fabf1.nell;\n let nend = fro1.nbn[n - 1];\n let lend = fro1.nbn[n - 1];\n\n for (let lk = 0; lk < lend; lk++) {\n let nodk = block1.nop[n - 1][lk];\n let ll;\n\n if (lcol === 0) {\n lcol++;\n ldest[lk] = lcol;\n fb1.lhed[lcol - 1] = nodk;\n } else {\n for (ll = 0; ll < lcol; ll++) {\n if (Math.abs(nodk) === Math.abs(fb1.lhed[ll])) break;\n }\n\n if (ll === lcol) {\n lcol++;\n ldest[lk] = lcol;\n fb1.lhed[lcol - 1] = nodk;\n } else {\n ldest[lk] = ll + 1;\n fb1.lhed[ll] = nodk;\n }\n }\n\n let kk;\n if (krow === 0) {\n krow++;\n kdest[lk] = krow;\n khed[krow - 1] = nodk;\n } else {\n for (kk = 0; kk < krow; kk++) {\n if (Math.abs(nodk) === Math.abs(khed[kk])) break;\n }\n\n if (kk === krow) {\n krow++;\n kdest[lk] = krow;\n khed[krow - 1] = nodk;\n } else {\n kdest[lk] = kk + 1;\n khed[kk] = nodk;\n }\n }\n }\n\n if (krow > nmax || lcol > nmax) {\n errorLog(\"Error: nmax-nsum not large enough\");\n return;\n }\n\n for (let l = 0; l < lend; l++) {\n let ll = ldest[l];\n for (let k = 0; k < nend; k++) {\n let kk = kdest[k];\n eq[kk - 1][ll - 1] += fabf1.estifm[k][l];\n }\n }\n\n let lc = 0;\n for (let l = 0; l < lcol; l++) {\n if (fb1.lhed[l] < 0) {\n lpiv[lc] = l + 1;\n lc++;\n }\n }\n\n let ir = 0;\n let kr = 0;\n for (let k = 0; k < krow; k++) {\n let kt = khed[k];\n if (kt < 0) {\n kpiv[kr] = k + 1;\n kr++;\n let kro = Math.abs(kt);\n if (block1.ncod[kro - 1] === 1) {\n jmod[ir] = k + 1;\n ir++;\n block1.ncod[kro - 1] = 2;\n block1.r1[kro - 1] = block1.bc[kro - 1];\n }\n }\n }\n\n if (ir > 0) {\n for (let irr = 0; irr < ir; irr++) {\n let k = jmod[irr] - 1;\n let kh = Math.abs(khed[k]);\n for (let l = 0; l < lcol; l++) {\n eq[k][l] = 0;\n let lh = Math.abs(fb1.lhed[l]);\n if (lh === kh) eq[k][l] = 1;\n }\n }\n }\n\n if (lc > nsum || fabf1.nell < block1.ne) {\n if (lc === 0) {\n errorLog(\"Error: no more rows fully summed\");\n return;\n }\n\n let kpivro = kpiv[0];\n let lpivco = lpiv[0];\n let pivot = eq[kpivro - 1][lpivco - 1];\n\n if (Math.abs(pivot) < 1e-4) {\n pivot = 0;\n for (let l = 0; l < lc; l++) {\n let lpivc = lpiv[l];\n for (let k = 0; k < kr; k++) {\n let kpivr = kpiv[k];\n let piva = eq[kpivr - 1][lpivc - 1];\n if (Math.abs(piva) > Math.abs(pivot)) {\n pivot = piva;\n lpivco = lpivc;\n kpivro = kpivr;\n }\n }\n }\n }\n\n let kro = Math.abs(khed[kpivro - 1]);\n lco = Math.abs(fb1.lhed[lpivco - 1]); // Assign, don't declare\n let nhlp = kro + lco + nrs[kro - 1] + ncs[lco - 1];\n fro1.det = (fro1.det * pivot * (-1) ** nhlp) / Math.abs(pivot);\n\n for (let iperm = 0; iperm < fro1.npt; iperm++) {\n if (iperm >= kro) nrs[iperm]--;\n if (iperm >= lco) ncs[iperm]--;\n }\n\n if (Math.abs(pivot) < 1e-10) {\n errorLog(\n `Warning: matrix singular or ill-conditioned, nell=${fabf1.nell}, kro=${kro}, lco=${lco}, pivot=${pivot}`\n );\n }\n\n if (pivot === 0) return;\n\n for (let l = 0; l < lcol; l++) {\n fb1.qq[l] = eq[kpivro - 1][l] / pivot;\n }\n\n let rhs = block1.r1[kro - 1] / pivot;\n block1.r1[kro - 1] = rhs;\n pvkol[kpivro - 1] = pivot;\n\n if (kpivro > 1) {\n for (let k = 0; k < kpivro - 1; k++) {\n let krw = Math.abs(khed[k]);\n let fac = eq[k][lpivco - 1];\n pvkol[k] = fac;\n if (lpivco > 1 && fac !== 0) {\n for (let l = 0; l < lpivco - 1; l++) {\n eq[k][l] -= fac * fb1.qq[l];\n }\n }\n if (lpivco < lcol) {\n for (let l = lpivco; l < lcol; l++) {\n eq[k][l - 1] = eq[k][l] - fac * fb1.qq[l];\n }\n }\n block1.r1[krw - 1] -= fac * rhs;\n }\n }\n\n if (kpivro < krow) {\n for (let k = kpivro; k < krow; k++) {\n let krw = Math.abs(khed[k]);\n let fac = eq[k][lpivco - 1];\n pvkol[k] = fac;\n if (lpivco > 1) {\n for (let l = 0; l < lpivco - 1; l++) {\n eq[k - 1][l] = eq[k][l] - fac * fb1.qq[l];\n }\n }\n if (lpivco < lcol) {\n for (let l = lpivco; l < lcol; l++) {\n eq[k - 1][l - 1] = eq[k][l] - fac * fb1.qq[l];\n }\n }\n block1.r1[krw - 1] -= fac * rhs;\n }\n }\n\n for (let i = 0; i < krow; i++) {\n fb1.ecpiv[ipiv + i - 1] = pvkol[i];\n }\n ipiv += krow;\n\n for (let i = 0; i < krow; i++) {\n fb1.ecpiv[ipiv + i - 1] = khed[i];\n }\n ipiv += krow;\n\n fb1.ecpiv[ipiv - 1] = kpivro;\n ipiv++;\n\n for (let i = 0; i < lcol; i++) {\n fb1.ecv[ice - 1 + i] = fb1.qq[i];\n }\n ice += lcol;\n\n for (let i = 0; i < lcol; i++) {\n fb1.ecv[ice - 1 + i] = fb1.lhed[i];\n }\n ice += lcol;\n\n fb1.ecv[ice - 1] = kro;\n fb1.ecv[ice] = lcol;\n fb1.ecv[ice + 1] = lpivco;\n fb1.ecv[ice + 2] = pivot;\n ice += 4;\n\n for (let k = 0; k < krow; k++) {\n eq[k][lcol - 1] = 0;\n }\n\n for (let l = 0; l < lcol; l++) {\n eq[krow - 1][l] = 0;\n }\n\n lcol--;\n if (lpivco < lcol + 1) {\n for (let l = lpivco - 1; l < lcol; l++) {\n fb1.lhed[l] = fb1.lhed[l + 1];\n }\n }\n\n krow--;\n if (kpivro < krow + 1) {\n for (let k = kpivro - 1; k < krow; k++) {\n khed[k] = khed[k + 1];\n }\n }\n\n if (krow > 1 || fabf1.nell < block1.ne) continue;\n\n lco = Math.abs(fb1.lhed[0]); // Assign, don't declare\n kpivro = 1;\n pivot = eq[0][0];\n kro = Math.abs(khed[0]);\n lpivco = 1;\n nhlp = kro + lco + nrs[kro - 1] + ncs[lco - 1];\n fro1.det = (fro1.det * pivot * (-1) ** nhlp) / Math.abs(pivot);\n\n fb1.qq[0] = 1;\n if (Math.abs(pivot) < 1e-10) {\n errorLog(\n `Warning: matrix singular or ill-conditioned, nell=${fabf1.nell}, kro=${kro}, lco=${lco}, pivot=${pivot}`\n );\n }\n\n if (pivot === 0) return;\n\n block1.r1[kro - 1] = block1.r1[kro - 1] / pivot;\n fb1.ecv[ice - 1] = fb1.qq[0];\n ice++;\n fb1.ecv[ice - 1] = fb1.lhed[0];\n ice++;\n fb1.ecv[ice - 1] = kro;\n fb1.ecv[ice] = lcol;\n fb1.ecv[ice + 1] = lpivco;\n fb1.ecv[ice + 2] = pivot;\n ice += 4;\n\n fb1.ecpiv[ipiv - 1] = pvkol[0];\n ipiv++;\n fb1.ecpiv[ipiv - 1] = khed[0];\n ipiv++;\n fb1.ecpiv[ipiv - 1] = kpivro;\n ipiv++;\n\n fro1.ice1 = ice;\n if (fro1.iwr1 === 1) debugLog(`total ecs transfer in matrix reduction=${ice}`);\n\n bacsub(ice);\n break;\n }\n }\n}\n\n// Back substitution\nfunction bacsub(ice) {\n for (let i = 0; i < fro1.npt; i++) {\n fro1.sk[i] = block1.bc[i];\n }\n\n for (let iv = 1; iv <= fro1.npt; iv++) {\n ice -= 4;\n let kro = fb1.ecv[ice - 1];\n let lcol = fb1.ecv[ice];\n let lpivco = fb1.ecv[ice + 1];\n let pivot = fb1.ecv[ice + 2];\n\n if (iv === 1) {\n ice--;\n fb1.lhed[0] = fb1.ecv[ice - 1];\n ice--;\n fb1.qq[0] = fb1.ecv[ice - 1];\n } else {\n ice -= lcol;\n for (let iii = 0; iii < lcol; iii++) {\n fb1.lhed[iii] = fb1.ecv[ice - 1 + iii];\n }\n ice -= lcol;\n for (let iii = 0; iii < lcol; iii++) {\n fb1.qq[iii] = fb1.ecv[ice - 1 + iii];\n }\n }\n\n let lco = Math.abs(fb1.lhed[lpivco - 1]);\n if (block1.ncod[lco - 1] > 0) continue;\n\n let gash = 0;\n fb1.qq[lpivco - 1] = 0;\n for (let l = 0; l < lcol; l++) {\n gash -= fb1.qq[l] * fro1.sk[Math.abs(fb1.lhed[l]) - 1];\n }\n\n fro1.sk[lco - 1] = gash + block1.r1[kro - 1];\n\n block1.ncod[lco - 1] = 1;\n }\n\n if (fro1.iwr1 === 1) debugLog(`value of ice after backsubstitution=${ice}`);\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport {\n initializeFEA,\n performIsoparametricMapping1D,\n performIsoparametricMapping2D,\n} from \"../mesh/meshUtilsScript.js\";\nimport { ThermalBoundaryConditions } from \"./thermalBoundaryConditionsScript.js\";\nimport { basicLog, debugLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the Jacobian matrix and residuals vector for the solid heat transfer model\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n */\nexport function assembleSolidHeatTransferMat(meshData, boundaryConditions) {\n basicLog(\"Starting solid heat transfer matrix assembly...\");\n\n // Extract mesh data\n const {\n nodesXCoordinates,\n nodesYCoordinates,\n nop,\n boundaryElements,\n totalElements,\n meshDimension,\n elementOrder,\n } = meshData;\n\n // Initialize FEA components\n const FEAData = initializeFEA(meshData);\n const {\n residualVector,\n jacobianMatrix,\n localToGlobalMap,\n basisFunctions,\n gaussPoints,\n gaussWeights,\n numNodes,\n } = FEAData;\n\n // Matrix assembly\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n // Map local element nodes to global mesh nodes\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n // Subtract 1 from nop in order to start numbering from 0\n localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // 1D solid heat transfer\n if (meshDimension === \"1D\") {\n // Get basis functions for the current Gauss point\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1]);\n\n // Perform isoparametric mapping\n const mappingResult = performIsoparametricMapping1D({\n basisFunction: basisFunctionsAndDerivatives.basisFunction,\n basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Extract mapping results\n const { detJacobian, basisFunctionDerivX } = mappingResult;\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n }\n // 2D solid heat transfer\n else if (meshDimension === \"2D\") {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Get basis functions for the current Gauss point\n let basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1],\n gaussPoints[gaussPointIndex2]\n );\n\n // Perform isoparametric mapping\n const mappingResult = performIsoparametricMapping2D({\n basisFunction: basisFunctionsAndDerivatives.basisFunction,\n basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi,\n basisFunctionDerivEta: basisFunctionsAndDerivatives.basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Extract mapping results\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = mappingResult;\n\n // Computation of Galerkin's residuals and Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n jacobianMatrix[localToGlobalMap1][localToGlobalMap2] +=\n -gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n }\n }\n }\n }\n }\n }\n\n // Apply boundary conditions\n basicLog(\"Applying thermal boundary conditions...\");\n const thermalBoundaryConditions = new ThermalBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Convection boundary conditions\n thermalBoundaryConditions.imposeConvectionBoundaryConditions(\n residualVector,\n jacobianMatrix,\n gaussPoints,\n gaussWeights,\n nodesXCoordinates,\n nodesYCoordinates,\n basisFunctions\n );\n basicLog(\"Convection boundary conditions applied\");\n\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Constant temperature boundary conditions applied\");\n\n // Print all residuals in debug mode\n debugLog(\"Residuals at each node:\");\n for (let i = 0; i < residualVector.length; i++) {\n debugLog(`Node ${i}: ${residualVector[i].toExponential(6)}`);\n }\n\n basicLog(\"Solid heat transfer matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n\n/**\n * Function to assemble the local Jacobian matrix and residuals vector for the solid heat transfer model when using the frontal system solver\n */\nexport function assembleSolidHeatTransferFront({\n elementIndex,\n nop,\n xCoordinates,\n yCoordinates,\n basisFunctions,\n gaussPoints,\n gaussWeights,\n ntopFlag = false,\n nlatFlag = false,\n convectionTop = { active: false, coeff: 0, extTemp: 0 }, // NEW\n}) {\n const numNodes = 9; // biquadratic 2D\n const estifm = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localLoad = Array(numNodes).fill(0);\n\n // Global node numbers (1-based in nop)\n const ngl = Array(numNodes);\n for (let i = 0; i < numNodes; i++) ngl[i] = Math.abs(nop[elementIndex][i]);\n\n // Volume (conductive) contribution\n for (let j = 0; j < gaussPoints.length; j++) {\n for (let k = 0; k < gaussPoints.length; k++) {\n const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } =\n basisFunctions.getBasisFunctions(gaussPoints[j], gaussPoints[k]);\n\n const localToGlobalMap = ngl.map((g) => g - 1);\n\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates: xCoordinates,\n nodesYCoordinates: yCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n for (let a = 0; a < numNodes; a++) {\n for (let b = 0; b < numNodes; b++) {\n estifm[a][b] -=\n gaussWeights[j] *\n gaussWeights[k] *\n detJacobian *\n (basisFunctionDerivX[a] * basisFunctionDerivX[b] +\n basisFunctionDerivY[a] * basisFunctionDerivY[b]);\n }\n }\n }\n }\n\n // Legacy natural boundary terms (top edge eta=1; right edge ksi=1) kept as in original frontal version\n // Replace previous generic top-edge load term with explicit Robin (convection) if requested\n if (ntopFlag && convectionTop.active) {\n const h = convectionTop.coeff;\n const Text = convectionTop.extTemp;\n // Integrate along top edge (eta = 1); local top edge nodes: 2,5,8\n for (let gp = 0; gp < gaussPoints.length; gp++) {\n const ksi = gaussPoints[gp];\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(ksi, 1);\n\n // Compute metric (edge length differential) |dx/dksi|\n let dx_dksi = 0, dy_dksi = 0;\n const topEdgeLocalNodes = [2, 5, 8];\n for (let n = 0; n < 9; n++) {\n const g = nop[elementIndex][n] - 1;\n dx_dksi += xCoordinates[g] * basisFunctionDerivKsi[n];\n dy_dksi += yCoordinates[g] * basisFunctionDerivKsi[n];\n }\n const ds_dksi = Math.sqrt(dx_dksi * dx_dksi + dy_dksi * dy_dksi);\n\n // Assemble Robin contributions\n for (const a of topEdgeLocalNodes) {\n for (const b of topEdgeLocalNodes) {\n estifm[a][b] -= gaussWeights[gp] * ds_dksi * h * basisFunction[a] * basisFunction[b];\n }\n localLoad[a] -= gaussWeights[gp] * ds_dksi * h * Text * basisFunction[a];\n }\n }\n } else if (ntopFlag && !convectionTop.active) {\n // If a zero-flux (symmetry) condition were applied on top, do nothing (natural BC)\n // (Previous placeholder load term removed to avoid unintended flux)\n }\n\n // If needed, similar patterned handling could be added for right edge (nlatFlag) later.\n\n return { estifm, localLoad, ngl };\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nconst proxyMarker = Symbol(\"Comlink.proxy\");\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\nconst finalizer = Symbol(\"Comlink.finalizer\");\nconst throwMarker = Symbol(\"Comlink.thrown\");\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler = {\n canHandle: (val) => isObject(val) && val[proxyMarker],\n serialize(obj) {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port1);\n return [port2, [port2]];\n },\n deserialize(port) {\n port.start();\n return wrap(port);\n },\n};\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler = {\n canHandle: (value) => isObject(value) && throwMarker in value,\n serialize({ value }) {\n let serialized;\n if (value instanceof Error) {\n serialized = {\n isError: true,\n value: {\n message: value.message,\n name: value.name,\n stack: value.stack,\n },\n };\n }\n else {\n serialized = { isError: false, value };\n }\n return [serialized, []];\n },\n deserialize(serialized) {\n if (serialized.isError) {\n throw Object.assign(new Error(serialized.value.message), serialized.value);\n }\n throw serialized.value;\n },\n};\n/**\n * Allows customizing the serialization of certain values.\n */\nconst transferHandlers = new Map([\n [\"proxy\", proxyTransferHandler],\n [\"throw\", throwTransferHandler],\n]);\nfunction isAllowedOrigin(allowedOrigins, origin) {\n for (const allowedOrigin of allowedOrigins) {\n if (origin === allowedOrigin || allowedOrigin === \"*\") {\n return true;\n }\n if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n return true;\n }\n }\n return false;\n}\nfunction expose(obj, ep = globalThis, allowedOrigins = [\"*\"]) {\n ep.addEventListener(\"message\", function callback(ev) {\n if (!ev || !ev.data) {\n return;\n }\n if (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n return;\n }\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\n let returnValue;\n try {\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\n switch (type) {\n case \"GET\" /* MessageType.GET */:\n {\n returnValue = rawValue;\n }\n break;\n case \"SET\" /* MessageType.SET */:\n {\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\n returnValue = true;\n }\n break;\n case \"APPLY\" /* MessageType.APPLY */:\n {\n returnValue = rawValue.apply(parent, argumentList);\n }\n break;\n case \"CONSTRUCT\" /* MessageType.CONSTRUCT */:\n {\n const value = new rawValue(...argumentList);\n returnValue = proxy(value);\n }\n break;\n case \"ENDPOINT\" /* MessageType.ENDPOINT */:\n {\n const { port1, port2 } = new MessageChannel();\n expose(obj, port2);\n returnValue = transfer(port1, [port1]);\n }\n break;\n case \"RELEASE\" /* MessageType.RELEASE */:\n {\n returnValue = undefined;\n }\n break;\n default:\n return;\n }\n }\n catch (value) {\n returnValue = { value, [throwMarker]: 0 };\n }\n Promise.resolve(returnValue)\n .catch((value) => {\n return { value, [throwMarker]: 0 };\n })\n .then((returnValue) => {\n const [wireValue, transferables] = toWireValue(returnValue);\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n if (type === \"RELEASE\" /* MessageType.RELEASE */) {\n // detach and deactive after sending release response above.\n ep.removeEventListener(\"message\", callback);\n closeEndPoint(ep);\n if (finalizer in obj && typeof obj[finalizer] === \"function\") {\n obj[finalizer]();\n }\n }\n })\n .catch((error) => {\n // Send Serialization Error To Caller\n const [wireValue, transferables] = toWireValue({\n value: new TypeError(\"Unserializable return value\"),\n [throwMarker]: 0,\n });\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\n });\n });\n if (ep.start) {\n ep.start();\n }\n}\nfunction isMessagePort(endpoint) {\n return endpoint.constructor.name === \"MessagePort\";\n}\nfunction closeEndPoint(endpoint) {\n if (isMessagePort(endpoint))\n endpoint.close();\n}\nfunction wrap(ep, target) {\n const pendingListeners = new Map();\n ep.addEventListener(\"message\", function handleMessage(ev) {\n const { data } = ev;\n if (!data || !data.id) {\n return;\n }\n const resolver = pendingListeners.get(data.id);\n if (!resolver) {\n return;\n }\n try {\n resolver(data);\n }\n finally {\n pendingListeners.delete(data.id);\n }\n });\n return createProxy(ep, pendingListeners, [], target);\n}\nfunction throwIfProxyReleased(isReleased) {\n if (isReleased) {\n throw new Error(\"Proxy has been released and is not useable\");\n }\n}\nfunction releaseEndpoint(ep) {\n return requestResponseMessage(ep, new Map(), {\n type: \"RELEASE\" /* MessageType.RELEASE */,\n }).then(() => {\n closeEndPoint(ep);\n });\n}\nconst proxyCounter = new WeakMap();\nconst proxyFinalizers = \"FinalizationRegistry\" in globalThis &&\n new FinalizationRegistry((ep) => {\n const newCount = (proxyCounter.get(ep) || 0) - 1;\n proxyCounter.set(ep, newCount);\n if (newCount === 0) {\n releaseEndpoint(ep);\n }\n });\nfunction registerProxy(proxy, ep) {\n const newCount = (proxyCounter.get(ep) || 0) + 1;\n proxyCounter.set(ep, newCount);\n if (proxyFinalizers) {\n proxyFinalizers.register(proxy, ep, proxy);\n }\n}\nfunction unregisterProxy(proxy) {\n if (proxyFinalizers) {\n proxyFinalizers.unregister(proxy);\n }\n}\nfunction createProxy(ep, pendingListeners, path = [], target = function () { }) {\n let isProxyReleased = false;\n const proxy = new Proxy(target, {\n get(_target, prop) {\n throwIfProxyReleased(isProxyReleased);\n if (prop === releaseProxy) {\n return () => {\n unregisterProxy(proxy);\n releaseEndpoint(ep);\n pendingListeners.clear();\n isProxyReleased = true;\n };\n }\n if (prop === \"then\") {\n if (path.length === 0) {\n return { then: () => proxy };\n }\n const r = requestResponseMessage(ep, pendingListeners, {\n type: \"GET\" /* MessageType.GET */,\n path: path.map((p) => p.toString()),\n }).then(fromWireValue);\n return r.then.bind(r);\n }\n return createProxy(ep, pendingListeners, [...path, prop]);\n },\n set(_target, prop, rawValue) {\n throwIfProxyReleased(isProxyReleased);\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n const [value, transferables] = toWireValue(rawValue);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"SET\" /* MessageType.SET */,\n path: [...path, prop].map((p) => p.toString()),\n value,\n }, transferables).then(fromWireValue);\n },\n apply(_target, _thisArg, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const last = path[path.length - 1];\n if (last === createEndpoint) {\n return requestResponseMessage(ep, pendingListeners, {\n type: \"ENDPOINT\" /* MessageType.ENDPOINT */,\n }).then(fromWireValue);\n }\n // We just pretend that `bind()` didn’t happen.\n if (last === \"bind\") {\n return createProxy(ep, pendingListeners, path.slice(0, -1));\n }\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"APPLY\" /* MessageType.APPLY */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n construct(_target, rawArgumentList) {\n throwIfProxyReleased(isProxyReleased);\n const [argumentList, transferables] = processArguments(rawArgumentList);\n return requestResponseMessage(ep, pendingListeners, {\n type: \"CONSTRUCT\" /* MessageType.CONSTRUCT */,\n path: path.map((p) => p.toString()),\n argumentList,\n }, transferables).then(fromWireValue);\n },\n });\n registerProxy(proxy, ep);\n return proxy;\n}\nfunction myFlat(arr) {\n return Array.prototype.concat.apply([], arr);\n}\nfunction processArguments(argumentList) {\n const processed = argumentList.map(toWireValue);\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\nconst transferCache = new WeakMap();\nfunction transfer(obj, transfers) {\n transferCache.set(obj, transfers);\n return obj;\n}\nfunction proxy(obj) {\n return Object.assign(obj, { [proxyMarker]: true });\n}\nfunction windowEndpoint(w, context = globalThis, targetOrigin = \"*\") {\n return {\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\n addEventListener: context.addEventListener.bind(context),\n removeEventListener: context.removeEventListener.bind(context),\n };\n}\nfunction toWireValue(value) {\n for (const [name, handler] of transferHandlers) {\n if (handler.canHandle(value)) {\n const [serializedValue, transferables] = handler.serialize(value);\n return [\n {\n type: \"HANDLER\" /* WireValueType.HANDLER */,\n name,\n value: serializedValue,\n },\n transferables,\n ];\n }\n }\n return [\n {\n type: \"RAW\" /* WireValueType.RAW */,\n value,\n },\n transferCache.get(value) || [],\n ];\n}\nfunction fromWireValue(value) {\n switch (value.type) {\n case \"HANDLER\" /* WireValueType.HANDLER */:\n return transferHandlers.get(value.name).deserialize(value.value);\n case \"RAW\" /* WireValueType.RAW */:\n return value.value;\n }\n}\nfunction requestResponseMessage(ep, pendingListeners, msg, transfers) {\n return new Promise((resolve) => {\n const id = generateUUID();\n pendingListeners.set(id, resolve);\n if (ep.start) {\n ep.start();\n }\n ep.postMessage(Object.assign({ id }, msg), transfers);\n });\n}\nfunction generateUUID() {\n return new Array(4)\n .fill(0)\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\n .join(\"-\");\n}\n\nexport { createEndpoint, expose, finalizer, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { prepareMesh } from \"./mesh/meshUtilsScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleSolidHeatTransferMat } from \"./solvers/solidHeatTransferScript.js\";\nimport { runFrontalSolver } from \"./methods/frontalSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"./utilities/loggingScript.js\";\n\n/**\n * Class to implement finite element analysis in JavaScript\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} meshConfig - Object containing computational mesh details\n * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis\n * @returns {object} An object containing the solution vector and additional mesh information\n */\nexport class FEAScriptModel {\n constructor() {\n this.solverConfig = null;\n this.meshConfig = {};\n this.boundaryConditions = {};\n this.solverMethod = \"lusolve\"; // Default solver method\n basicLog(\"FEAScriptModel instance created\");\n }\n\n setSolverConfig(solverConfig) {\n this.solverConfig = solverConfig;\n debugLog(`Solver config set to: ${solverConfig}`);\n }\n\n setMeshConfig(meshConfig) {\n this.meshConfig = meshConfig;\n debugLog(`Mesh config set with dimensions: ${meshConfig.meshDimension}`);\n }\n\n addBoundaryCondition(boundaryKey, condition) {\n this.boundaryConditions[boundaryKey] = condition;\n debugLog(`Boundary condition added for boundary: ${boundaryKey}, type: ${condition[0]}`);\n }\n\n setSolverMethod(solverMethod) {\n this.solverMethod = solverMethod;\n debugLog(`Solver method set to: ${solverMethod}`);\n }\n\n solve() {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n const error = \"Solver config, mesh config, and boundary conditions must be set before solving.\";\n console.error(error);\n throw new Error(error);\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n let initialSolution = [];\n\n // Prepare the mesh\n basicLog(\"Preparing mesh...\");\n const meshData = prepareMesh(this.meshConfig);\n basicLog(\"Mesh preparation completed\");\n\n // Extract node coordinates from meshData\n const nodesCoordinates = {\n nodesXCoordinates: meshData.nodesXCoordinates,\n nodesYCoordinates: meshData.nodesYCoordinates,\n };\n\n // Select and execute the appropriate solver based on solverConfig\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n if (this.solverConfig === \"solidHeatTransferScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Check if using frontal solver\n if (this.solverMethod === \"frontal\") {\n basicLog(`Using frontal solver method`);\n // Call frontal solver\n const frontalResult = runFrontalSolver(this.meshConfig, this.boundaryConditions);\n solutionVector = frontalResult.solutionVector;\n } else {\n // Use regular linear solver methods\n ({ jacobianMatrix, residualVector } = assembleSolidHeatTransferMat(\n meshData,\n this.boundaryConditions\n ));\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\n }\n } else if (this.solverConfig === \"frontPropagationScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Initialize eikonalActivationFlag\n let eikonalActivationFlag = 0;\n const eikonalExteralIterations = 5; // Number of incremental steps for the eikonal equation\n\n // Create context object with all necessary properties\n const context = {\n meshData: meshData,\n boundaryConditions: this.boundaryConditions,\n eikonalActivationFlag: eikonalActivationFlag,\n solverMethod: this.solverMethod,\n initialSolution,\n };\n\n while (eikonalActivationFlag <= 1) {\n // Update the context object with current eikonalActivationFlag\n context.eikonalActivationFlag = eikonalActivationFlag;\n\n // Pass the previous solution as initial guess\n if (solutionVector.length > 0) {\n context.initialSolution = [...solutionVector];\n }\n\n // Solve the assembled non-linear system\n const newtonRaphsonResult = newtonRaphson(assembleFrontPropagationMat, context, 100, 1e-4);\n\n // Extract results\n jacobianMatrix = newtonRaphsonResult.jacobianMatrix;\n residualVector = newtonRaphsonResult.residualVector;\n solutionVector = newtonRaphsonResult.solutionVector;\n\n // Increment for next iteration\n eikonalActivationFlag += 1 / eikonalExteralIterations;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// External imports\nimport * as Comlink from \"../vendor/comlink.mjs\";\n\n// Internal imports\nimport { basicLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Class to facilitate communication with web workers for FEAScript operations\n */\nexport class FEAScriptWorker {\n /**\n * Constructor to initialize the FEAScriptWorker class\n * Sets up the worker and initializes the workerWrapper.\n */\n constructor() {\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n\n this._initWorker();\n }\n\n /**\n * Function to initialize the web worker and wrap it using Comlink.\n * @private\n * @throws Will throw an error if the worker fails to initialize.\n */\n async _initWorker() {\n try {\n this.worker = new Worker(new URL(\"./wrapperScript.js\", import.meta.url), {\n type: \"module\",\n });\n\n this.worker.onerror = (event) => {\n console.error(\"FEAScriptWorker: Worker error:\", event);\n };\n const workerWrapper = Comlink.wrap(this.worker);\n\n this.feaWorker = await new workerWrapper();\n\n this.isReady = true;\n } catch (error) {\n console.error(\"Failed to initialize worker\", error);\n throw error;\n }\n }\n\n /**\n * Function to ensure that the worker is ready before performing any operations.\n * @private\n * @returns {Promise} Resolves when the worker is ready.\n * @throws Will throw an error if the worker is not ready within the timeout period.\n */\n async _ensureReady() {\n if (this.isReady) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds max\n\n const checkReady = () => {\n attempts++;\n if (this.isReady) {\n resolve();\n } else if (attempts >= maxAttempts) {\n reject(new Error(\"Timeout waiting for worker to be ready\"));\n } else {\n setTimeout(checkReady, 1000);\n }\n };\n checkReady();\n });\n }\n\n /**\n * Function to set the solver configuration in the worker.\n * @param {string} solverConfig - The solver configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setSolverConfig(solverConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver config to: ${solverConfig}`);\n return this.feaWorker.setSolverConfig(solverConfig);\n }\n\n /**\n * Sets the mesh configuration in the worker.\n * @param {object} meshConfig - The mesh configuration to set.\n * @returns {Promise} Resolves when the configuration is set.\n */\n async setMeshConfig(meshConfig) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting mesh config`);\n return this.feaWorker.setMeshConfig(meshConfig);\n }\n\n /**\n * Adds a boundary condition to the worker.\n * @param {string} boundaryKey - The key identifying the boundary.\n * @param {array} condition - The boundary condition to add.\n * @returns {Promise} Resolves when the boundary condition is added.\n */\n async addBoundaryCondition(boundaryKey, condition) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Adding boundary condition for boundary: ${boundaryKey}`);\n return this.feaWorker.addBoundaryCondition(boundaryKey, condition);\n }\n\n /**\n * Sets the solver method in the worker.\n * @param {string} solverMethod - The solver method to set.\n * @returns {Promise} Resolves when the solver method is set.\n */\n async setSolverMethod(solverMethod) {\n await this._ensureReady();\n basicLog(`FEAScriptWorker: Setting solver method to: ${solverMethod}`);\n return this.feaWorker.setSolverMethod(solverMethod);\n }\n\n /**\n * Requests the worker to solve the problem.\n * @returns {Promise} Resolves with the solution result.\n */\n async solve() {\n await this._ensureReady();\n basicLog(\"FEAScriptWorker: Requesting solution from worker...\");\n\n const startTime = performance.now();\n const result = await this.feaWorker.solve();\n const endTime = performance.now();\n\n basicLog(`FEAScriptWorker: Solution completed in ${((endTime - startTime) / 1000).toFixed(2)}s`);\n return result;\n }\n\n /**\n * Retrieves model information from the worker.\n * @returns {Promise} Resolves with the model information.\n */\n async getModelInfo() {\n await this._ensureReady();\n return this.feaWorker.getModelInfo();\n }\n\n /**\n * Sends a ping request to the worker to check its availability.\n * @returns {Promise} Resolves if the worker responds.\n */\n async ping() {\n await this._ensureReady();\n return this.feaWorker.ping();\n }\n\n /**\n * Terminates the worker and cleans up resources.\n */\n terminate() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.feaWorker = null;\n this.isReady = false;\n }\n }\n}\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\";\nexport { logSystem, printVersion } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const VERSION = \"0.1.3\";","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n// Internal imports\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to import mesh data from Gmsh format containing quadrilateral and triangular elements\n * @param {File} file - The Gmsh file to be parsed (.msh version 4.1)\n * @returns {object} The parsed mesh data including node coordinates, element connectivity, and boundary conditions\n */\nconst importGmshQuadTri = async (file) => {\n let result = {\n nodesXCoordinates: [],\n nodesYCoordinates: [],\n nodalNumbering: {\n quadElements: [],\n triangleElements: [],\n },\n boundaryElements: [],\n boundaryConditions: [],\n boundaryNodePairs: {}, // Store boundary node pairs for processing in meshGenerationScript\n gmshV: 0,\n ascii: false,\n fltBytes: \"8\",\n totalNodesX: 0,\n totalNodesY: 0,\n physicalPropMap: [],\n elementTypes: {},\n };\n\n let content = await file.text();\n let lines = content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\" && line !== \" \");\n\n let section = \"\";\n let lineIndex = 0;\n\n let nodeEntityBlocks = 0;\n let totalNodes = 0;\n let nodeBlocksProcessed = 0;\n let currentNodeBlock = { numNodes: 0 };\n let nodeTagsCollected = 0;\n let nodeTags = [];\n let nodeCoordinatesCollected = 0;\n\n let elementEntityBlocks = 0;\n let totalElements = 0;\n let elementBlocksProcessed = 0;\n let currentElementBlock = {\n dim: 0,\n tag: 0,\n elementType: 0,\n numElements: 0,\n };\n let elementsProcessedInBlock = 0;\n\n let boundaryElementsByTag = {};\n\n while (lineIndex < lines.length) {\n const line = lines[lineIndex];\n\n if (line === \"$MeshFormat\") {\n section = \"meshFormat\";\n lineIndex++;\n continue;\n } else if (line === \"$EndMeshFormat\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$PhysicalNames\") {\n section = \"physicalNames\";\n lineIndex++;\n continue;\n } else if (line === \"$EndPhysicalNames\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Entities\") {\n section = \"entities\";\n lineIndex++;\n continue;\n } else if (line === \"$EndEntities\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Nodes\") {\n section = \"nodes\";\n lineIndex++;\n continue;\n } else if (line === \"$EndNodes\") {\n section = \"\";\n lineIndex++;\n continue;\n } else if (line === \"$Elements\") {\n section = \"elements\";\n lineIndex++;\n continue;\n } else if (line === \"$EndElements\") {\n section = \"\";\n lineIndex++;\n continue;\n }\n\n const parts = line.split(/\\s+/).filter((part) => part !== \"\");\n\n if (section === \"meshFormat\") {\n result.gmshV = parseFloat(parts[0]);\n result.ascii = parts[1] === \"0\";\n result.fltBytes = parts[2];\n } else if (section === \"physicalNames\") {\n if (parts.length >= 3) {\n if (!/^\\d+$/.test(parts[0])) {\n lineIndex++;\n continue;\n }\n\n const dimension = parseInt(parts[0], 10);\n const tag = parseInt(parts[1], 10);\n let name = parts.slice(2).join(\" \");\n name = name.replace(/^\"|\"$/g, \"\");\n\n result.physicalPropMap.push({\n tag,\n dimension,\n name,\n });\n }\n } else if (section === \"nodes\") {\n if (nodeEntityBlocks === 0) {\n nodeEntityBlocks = parseInt(parts[0], 10);\n totalNodes = parseInt(parts[1], 10);\n result.nodesXCoordinates = new Array(totalNodes).fill(0);\n result.nodesYCoordinates = new Array(totalNodes).fill(0);\n lineIndex++;\n continue;\n }\n\n if (nodeBlocksProcessed < nodeEntityBlocks && currentNodeBlock.numNodes === 0) {\n currentNodeBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n parametric: parseInt(parts[2], 10),\n numNodes: parseInt(parts[3], 10),\n };\n\n nodeTags = [];\n nodeTagsCollected = 0;\n nodeCoordinatesCollected = 0;\n\n lineIndex++;\n continue;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n for (let i = 0; i < parts.length && nodeTagsCollected < currentNodeBlock.numNodes; i++) {\n nodeTags.push(parseInt(parts[i], 10));\n nodeTagsCollected++;\n }\n\n if (nodeTagsCollected < currentNodeBlock.numNodes) {\n lineIndex++;\n continue;\n }\n\n lineIndex++;\n continue;\n }\n\n if (nodeCoordinatesCollected < currentNodeBlock.numNodes) {\n const nodeTag = nodeTags[nodeCoordinatesCollected] - 1;\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n\n result.nodesXCoordinates[nodeTag] = x;\n result.nodesYCoordinates[nodeTag] = y;\n result.totalNodesX++;\n result.totalNodesY++;\n\n nodeCoordinatesCollected++;\n\n if (nodeCoordinatesCollected === currentNodeBlock.numNodes) {\n nodeBlocksProcessed++;\n currentNodeBlock = { numNodes: 0 };\n }\n }\n } else if (section === \"elements\") {\n if (elementEntityBlocks === 0) {\n elementEntityBlocks = parseInt(parts[0], 10);\n totalElements = parseInt(parts[1], 10);\n lineIndex++;\n continue;\n }\n\n if (elementBlocksProcessed < elementEntityBlocks && currentElementBlock.numElements === 0) {\n currentElementBlock = {\n dim: parseInt(parts[0], 10),\n tag: parseInt(parts[1], 10),\n elementType: parseInt(parts[2], 10),\n numElements: parseInt(parts[3], 10),\n };\n\n result.elementTypes[currentElementBlock.elementType] =\n (result.elementTypes[currentElementBlock.elementType] || 0) + currentElementBlock.numElements;\n\n elementsProcessedInBlock = 0;\n lineIndex++;\n continue;\n }\n\n if (elementsProcessedInBlock < currentElementBlock.numElements) {\n const elementTag = parseInt(parts[0], 10);\n const nodeIndices = parts.slice(1).map((idx) => parseInt(idx, 10));\n\n if (currentElementBlock.elementType === 1 || currentElementBlock.elementType === 8) {\n const physicalTag = currentElementBlock.tag;\n\n if (!boundaryElementsByTag[physicalTag]) {\n boundaryElementsByTag[physicalTag] = [];\n }\n\n boundaryElementsByTag[physicalTag].push(nodeIndices);\n\n // Store boundary node pairs for later processing in meshGenerationScript\n if (!result.boundaryNodePairs[physicalTag]) {\n result.boundaryNodePairs[physicalTag] = [];\n }\n result.boundaryNodePairs[physicalTag].push(nodeIndices);\n } else if (currentElementBlock.elementType === 2) {\n // Linear triangle elements (3 nodes)\n result.nodalNumbering.triangleElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 3) {\n // Linear quadrilateral elements (4 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n } else if (currentElementBlock.elementType === 10) {\n // Quadratic quadrilateral elements (9 nodes)\n result.nodalNumbering.quadElements.push(nodeIndices);\n }\n\n elementsProcessedInBlock++;\n\n if (elementsProcessedInBlock === currentElementBlock.numElements) {\n elementBlocksProcessed++;\n currentElementBlock = { numElements: 0 };\n }\n }\n }\n\n lineIndex++;\n }\n\n // Store boundary conditions information\n result.physicalPropMap.forEach((prop) => {\n if (prop.dimension === 1) {\n const boundaryNodes = boundaryElementsByTag[prop.tag] || [];\n\n if (boundaryNodes.length > 0) {\n result.boundaryConditions.push({\n name: prop.name,\n tag: prop.tag,\n nodes: boundaryNodes,\n });\n }\n }\n });\n\n debugLog(\n `Parsed boundary node pairs by physical tag: ${JSON.stringify(\n result.boundaryNodePairs\n )}. These pairs will be used to identify boundary elements in the mesh.`\n );\n\n return result;\n};\n\nexport { importGmshQuadTri };\n","// ______ ______ _____ _ _ //\n// | ____| ____| /\\ / ____| (_) | | //\n// | |__ | |__ / \\ | (___ ___ ____ _ ____ | |_ //\n// | __| | __| / /\\ \\ \\___ \\ / __| __| | _ \\| __| //\n// | | | |____ / ____ \\ ____) | (__| | | | |_) | | //\n// |_| |______/_/ \\_\\_____/ \\___|_| |_| __/| | //\n// | | | | //\n// |_| | |_ //\n// Website: https://feascript.com/ \\__| //\n\n/**\n * Function to create plots of the solution vector\n * @param {*} solutionVector - The computed solution vector\n * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {string} meshDimension - The dimension of the solution\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n * @param {string} [meshType=\"structured\"] - Type of mesh: \"structured\" or \"unstructured\"\n */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId,\n meshType = \"structured\"\n) {\n const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates;\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // Check if solutionVector is a nested array\n let yData;\n if (solutionVector.length > 0 && Array.isArray(solutionVector[0])) {\n yData = solutionVector.map((arr) => arr[0]);\n } else {\n yData = solutionVector;\n }\n let xData = Array.from(nodesXCoordinates);\n\n let lineData = {\n x: xData,\n y: yData,\n mode: \"lines\",\n type: \"scatter\",\n line: { color: \"rgb(219, 64, 82)\", width: 2 },\n name: \"Solution\",\n };\n\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxPlotWidth = Math.max(...xData);\n let zoomFactor = maxWindowWidth / maxPlotWidth;\n let plotWidth = Math.max(zoomFactor * maxPlotWidth, 400);\n let plotHeight = 350;\n\n let layout = {\n title: `line plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"Solution\" },\n margin: { l: 70, r: 40, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Use the user-provided mesh type\n const isStructured = meshType === \"structured\";\n \n // For auto-detection (if needed)\n const uniqueXCoords = new Set(nodesXCoordinates).size;\n const uniqueYCoords = new Set(nodesYCoordinates).size;\n \n // Extract scalar values from solution vector\n let zValues;\n if (Array.isArray(solutionVector[0])) {\n zValues = solutionVector.map(val => val[0]);\n } else {\n zValues = solutionVector;\n }\n \n // Common sizing parameters for both plot types\n let maxWindowWidth = Math.min(window.innerWidth, 700);\n let maxX = Math.max(...nodesXCoordinates);\n let maxY = Math.max(...nodesYCoordinates);\n let aspectRatio = maxY / maxX;\n let plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = plotWidth * aspectRatio * 0.8; // Slightly reduce height for better appearance\n \n // Common layout properties\n let layout = {\n title: `${plotType} plot - ${solverConfig}`,\n width: plotWidth,\n height: plotHeight,\n xaxis: { title: \"x\" },\n yaxis: { title: \"y\" },\n margin: { l: 50, r: 50, t: 50, b: 50 },\n hovermode: 'closest'\n };\n \n if (isStructured) {\n // Calculate the number of nodes along the x-axis and y-axis\n const numNodesX = uniqueXCoords;\n const numNodesY = uniqueYCoords;\n\n // Reshape the nodesXCoordinates and nodesYCoordinates arrays to match the grid dimensions\n let reshapedXCoordinates = math.reshape(Array.from(nodesXCoordinates), [numNodesX, numNodesY]);\n let reshapedYCoordinates = math.reshape(Array.from(nodesYCoordinates), [numNodesX, numNodesY]);\n\n // Reshape the solution array to match the grid dimensions\n let reshapedSolution = math.reshape(Array.from(solutionVector), [numNodesX, numNodesY]);\n\n // Transpose the reshapedSolution array to get column-wise data\n let transposedSolution = math.transpose(reshapedSolution);\n\n // Create an array for x-coordinates used in the contour plot\n let reshapedXForPlot = [];\n for (let i = 0; i < numNodesX * numNodesY; i += numNodesY) {\n let xValue = nodesXCoordinates[i];\n reshapedXForPlot.push(xValue);\n }\n\n // Create the data structure for the contour plot\n let contourData = {\n z: transposedSolution,\n type: \"contour\",\n contours: {\n coloring: \"heatmap\",\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n x: reshapedXForPlot,\n y: reshapedYCoordinates[0],\n name: 'Solution Field'\n };\n\n // Create the plot using Plotly\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n } else {\n // Create an interpolated contour plot for the unstructured mesh\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zValues,\n type: 'contour',\n contours: {\n coloring: 'heatmap',\n showlabels: false\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: 'Solution'\n },\n name: 'Solution Field'\n };\n \n // Create the plot using only the contour fill\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n }\n}\n"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","debugLog","message","console","log","basicLog","errorLog","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","jacobianMatrixSparse","math","sparse","luFactorization","slu","solutionMatrix","lusolve","squeeze","valueOf","jacobiSolverResult","initialGuess","n","x","xNew","Array","iteration","sum","j","maxDiff","max","abs","jacobiSolver","fill","timeEnd","newtonRaphson","assembleMat","context","errorNorm","deltaX","totalNodes","meshData","nodesXCoordinates","initialSolution","Number","boundaryConditions","eikonalActivationFlag","toExponential","BasisFunctions","constructor","meshDimension","elementOrder","this","getBasisFunctions","ksi","eta","basisFunction","basisFunctionDerivKsi","basisFunctionDerivEta","l1","c","l2","l3","dl1","dl2","dl3","Mesh","numElementsX","maxX","numElementsY","maxY","parsedMesh","boundaryElementsProcessed","parseMeshFromGmsh","nodalNumbering","isArray","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","boundaryElements","undefined","fixedBoundaryElements","boundaryNodePairs","forEach","prop","dimension","tag","nodesPair","node1","node2","name","foundElement","elemNodes","includes","side","node1Index","indexOf","node2Index","join","Mesh1D","super","generateMesh","totalNodesX","nodeIndex","generate1DNodalNumbering","findBoundaryElements","nop","elementIndex","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generate2DNodalNumbering","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","initializeFEA","colIndex","basisFunctions","gaussPointsAndWeights","localToGlobalMap","numNodes","performIsoparametricMapping1D","params","xCoordinates","ksiDerivX","localNodeIndex","detJacobian","basisFunctionDerivX","performIsoparametricMapping2D","yCoordinates","etaDerivX","ksiDerivY","etaDerivY","basisFunctionDerivY","GenericBoundaryConditions","imposeConstantValueBoundaryConditions","Object","keys","boundaryKey","value","globalNodeIndex","assembleFrontPropagationMat","eikonalViscousTerm","totalElements","FEAData","gaussPointIndex1","basisFunctionsAndDerivatives","mappingResult","solutionDerivX","localNodeIndex1","localNodeIndex2","gaussPointIndex2","solutionDerivY","localToGlobalMap1","localToGlobalMap2","ThermalBoundaryConditions","imposeConstantTempBoundaryConditions","tempValue","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","tangentVectorLength","globalNodeIndex2","gaussPointIndex","runFrontalSolver","meshConfig","block1","nex","ney","xorigin","yorigin","xlast","ylast","deltax","deltay","xydiscr","ne","nnx","nny","np","nel","k","l","nodnumb","xpt","ypt","xycoord","ncod","bc","col","ntop","nlat","r1","fro1","npt","iwr1","ntra","det","nbn","lco","ldest","kdest","khed","nmax","kpiv","lpiv","jmod","pvkol","eq","map","nrs","nnmax","ncs","check","ice","ipiv","nsum","fabf1","nell","nep","lcol","krow","abfind","nend","lend","lk","ll","kk","nodk","fb1","lhed","estifm","lc","ir","kr","kt","kro","irr","kh","kpivro","lpivco","pivot","lpivc","kpivr","piva","nhlp","iperm","qq","rhs","krw","fac","ecpiv","ecv","ice1","bacsub","front","u","sk","main","slice","nodesCoordinates","nemax","gauss","w","gp","basisFunctionsLib","localLoad","ngl","ntopFlag","nlatFlag","convectionTop","active","coeff","g","a","b","h","Text","dx_dksi","dy_dksi","topEdgeLocalNodes","ds_dksi","assembleSolidHeatTransferFront","iv","iii","gash","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","serialized","Error","isError","stack","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","fromWireValue","returnValue","parent","reduce","rawValue","apply","proxy","transfers","transferCache","set","transfer","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","isMessagePort","close","target","pendingListeners","resolver","get","delete","createProxy","throwIfProxyReleased","isReleased","releaseEndpoint","requestResponseMessage","proxyCounter","WeakMap","proxyFinalizers","FinalizationRegistry","newCount","isProxyReleased","Proxy","_target","unregister","unregisterProxy","clear","r","p","toString","bind","_thisArg","rawArgumentList","last","processArguments","construct","register","registerProxy","processed","v","arr","prototype","concat","handler","serializedValue","msg","floor","random","MAX_SAFE_INTEGER","solverConfig","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","mesh","nodesCoordinatesAndNumbering","prepareMesh","thermalBoundaryConditions","assembleSolidHeatTransferMat","eikonalExteralIterations","newtonRaphsonResult","worker","feaWorker","isReady","_initWorker","Worker","URL","document","location","require","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","onerror","event","workerWrapper","Comlink.wrap","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","result","toFixed","getModelInfo","ping","terminate","async","file","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","numElements","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","parseInt","replace","parametric","nodeTag","y","nodeIndices","idx","physicalTag","boundaryNodes","nodes","level","plotType","plotDivId","meshType","yData","xData","from","lineData","mode","color","width","maxWindowWidth","min","window","innerWidth","maxPlotWidth","zoomFactor","layout","title","height","xaxis","yaxis","margin","t","Plotly","newPlot","responsive","isStructured","uniqueXCoords","Set","size","uniqueYCoords","zValues","aspectRatio","plotWidth","hovermode","numNodesX","numNodesY","reshape","reshapedYCoordinates","reshapedSolution","transposedSolution","transpose","reshapedXForPlot","xValue","contourData","z","contours","coloring","showlabels","colorbar","commitResponse","fetch","commitData","json","latestCommitDate","Date","commit","committer","date","toLocaleString"],"mappings":"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"} \ No newline at end of file