diff --git a/README.md b/README.md index 7a021c4..5fcd844 100644 --- a/README.md +++ b/README.md @@ -156,8 +156,11 @@ Here is a minimal browser-based example using the JavaScript API. Adapt paths, s > 💖 **If you find FEAScript useful, please consider supporting its development through a donation:** + + GitHub Sponsors + - Donate using Liberapay + Donate using Liberapay Your support helps ensure the continued development and maintenance of this project. diff --git a/dist/feascript.cjs.js b/dist/feascript.cjs.js index c3b486c..28463e3 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 N=Symbol("Comlink.proxy"),w=Symbol("Comlink.endpoint"),O=Symbol("Comlink.releaseProxy"),S=Symbol("Comlink.finalizer"),X=Symbol("Comlink.thrown"),V=e=>"object"==typeof e&&null!==e||"function"==typeof e,T=new Map([["proxy",{canHandle:e=>V(e)&&e[N],serialize(e){const{port1:t,port2:n}=new MessageChannel;return k(e,t),[n,[n]]},deserialize:e=>(e.start(),R(e))}],["throw",{canHandle:e=>V(e)&&X 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 k(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(J);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]]=J(s.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[N]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;k(e,n),d=function(e,t){return G.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[X]:0}}Promise.resolve(d).catch((e=>({value:e,[X]:0}))).then((n=>{const[s,a]=K(n);t.postMessage(Object.assign(Object.assign({},s),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",o),P(t),S in e&&"function"==typeof e[S]&&e[S]())})).catch((e=>{const[n,o]=K({value:new TypeError("Unserializable return value"),[X]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),o)}))})),t.start&&t.start()}function P(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function R(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)}})),j(e,n,[],t)}function Y(e){if(e)throw new Error("Proxy has been released and is not useable")}function I(e){return H(e,new Map,{type:"RELEASE"}).then((()=>{P(e)}))}const B=new WeakMap,q="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(B.get(e)||0)-1;B.set(e,t),0===t&&I(e)}));function j(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(Y(s),r===O)return()=>{!function(e){q&&q.unregister(e)}(i),I(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=H(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(J);return o.then.bind(o)}return j(e,t,[...n,r])},set(o,i,r){Y(s);const[a,l]=K(r);return H(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(J)},apply(o,i,r){Y(s);const a=n[n.length-1];if(a===w)return H(e,t,{type:"ENDPOINT"}).then(J);if("bind"===a)return j(e,t,n.slice(0,-1));const[l,d]=W(r);return H(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(J)},construct(o,i){Y(s);const[r,a]=W(i);return H(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(J)}});return function(e,t){const n=(B.get(t)||0)+1;B.set(t,n),q&&q.register(e,t,e)}(i,e),i}function W(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 G=new WeakMap;function K(e){for(const[t,n]of T)if(n.canHandle(e)){const[o,s]=n.serialize(e);return[{type:"HANDLER",name:t,value:o},s]}return[{type:"RAW",value:e},G.get(e)||[]]}function J(e){switch(e.type){case"HANDLER":return T.get(e.name).deserialize(e.value);case"RAW":return e.value}}function H(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",this.coefficientFunctions=null,o("FEAScriptModel instance created")}setSolverConfig(e,t={}){this.solverConfig=e,t&&t.coefficientFunctions&&(this.coefficientFunctions=t.coefficientFunctions,n("Coefficient functions set")),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=[],r=[],a=[];o("Preparing mesh...");const u=function(e){const{meshDimension:t,numElementsX:o,numElementsY:i,maxX:r,maxY:a,elementOrder:u,parsedMesh:c}=e;let m;"1D"===t?m=new l({numElementsX:o,maxX:r,elementOrder:u,parsedMesh:c}):"2D"===t?m=new d({numElementsX:o,maxX:r,numElementsY:i,maxY:a,elementOrder:u,parsedMesh:c}):s("Mesh dimension must be either '1D' or '2D'.");const h=m.boundaryElementsProcessed?m.parsedMesh:m.generateMesh();let f,p,b=h.nodesXCoordinates,y=h.nodesYCoordinates,g=h.totalNodesX,E=h.totalNodesY,v=h.nodalNumbering,M=h.boundaryElements;return null!=c?(f=v.length,p=b.length,n(`Using parsed mesh with ${f} elements and ${p} nodes`)):(f=o*("2D"===t?i:1),p=g*("2D"===t?E:1),n(`Using mesh generated from geometry with ${f} elements and ${p} nodes`)),{nodesXCoordinates:b,nodesYCoordinates:y,totalNodesX:g,totalNodesY:E,nop:v,boundaryElements:M,totalElements:f,totalNodes:p,meshDimension:t,elementOrder:u}}(this.meshConfig);o("Mesh preparation completed");const g={nodesXCoordinates:u.nodesXCoordinates,nodesYCoordinates:u.nodesYCoordinates};if(o("Beginning solving process..."),console.time("totalSolvingTime"),"heatConductionScript"===this.solverConfig)if(o(`Using solver: ${this.solverConfig}`),"frontal"===this.solverMethod){r=$(p,u,this.boundaryConditions).solutionVector}else{({jacobianMatrix:e,residualVector:t}=function(e,t){o("Starting solid heat transfer matrix assembly...");const{nodesXCoordinates:n,nodesYCoordinates:s,nop:i,boundaryElements:r,totalElements:a,meshDimension:l,elementOrder:d}=e,u=c(e),{residualVector:p,jacobianMatrix:b,localToGlobalMap:y,basisFunctions:g,gaussPoints:E,gaussWeights:v,numNodes:M}=u;for(let e=0;e0&&(i.initialSolution=[...r]);const o=A(y,i,100,1e-4);e=o.jacobianMatrix,t=o.residualVector,r=o.solutionVector,n+=1/s}}else if("generalFormPDEScript"===this.solverConfig)if(o(`Using solver: ${this.solverConfig}`),"frontal"===this.solverMethod)s("Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.");else{({jacobianMatrix:e,residualVector:t}=function(e,t,n){o("Starting general form PDE matrix assembly...");const{nodesXCoordinates:i,nodesYCoordinates:r,nop:a,boundaryElements:l,totalElements:d,meshDimension:u,elementOrder:h}=e,{A:f,B:p,C:y,D:g}=n,E=c(e),{residualVector:v,jacobianMatrix:M,localToGlobalMap:C,basisFunctions:D,gaussPoints:$,gaussWeights:F,numNodes:x}=E;if("1D"===u)for(let e=0;e{console.error("FEAScriptWorker: Worker error:",e)};const e=R(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.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},u=0,c=[],m=0,h=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},b=0,y={};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;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);b++,b===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,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,u={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],u,{responsive:!0})}else if("2D"===o&&"contour"===s){const t="structured"===r,o=new Set(a).size,d=new Set(l).size;let u;u=Array.isArray(e[0])?e.map((e=>e[0])):e;let c=Math.min(window.innerWidth,700),m=Math.max(...a),h=Math.max(...l)/m,f=Math.min(c,600),p={title:`${s} plot - ${n}`,width:f,height:f*h*.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]),u=math.transpose(r),c=[];for(let e=0;e"object"==typeof e&&null!==e||"function"==typeof e,T=new Map([["proxy",{canHandle:e=>V(e)&&e[N],serialize(e){const{port1:t,port2:n}=new MessageChannel;return k(e,t),[n,[n]]},deserialize:e=>(e.start(),R(e))}],["throw",{canHandle:e=>V(e)&&X 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 k(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(J);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]]=J(s.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[N]:!0})}(new n(...l));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;k(e,n),d=function(e,t){return G.set(e,t),e}(t,[t])}break;case"RELEASE":d=void 0;break;default:return}}catch(e){d={value:e,[X]:0}}Promise.resolve(d).catch((e=>({value:e,[X]:0}))).then((n=>{const[s,a]=K(n);t.postMessage(Object.assign(Object.assign({},s),{id:i}),a),"RELEASE"===r&&(t.removeEventListener("message",o),P(t),S in e&&"function"==typeof e[S]&&e[S]())})).catch((e=>{const[n,o]=K({value:new TypeError("Unserializable return value"),[X]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),o)}))})),t.start&&t.start()}function P(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function R(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)}})),j(e,n,[],t)}function Y(e){if(e)throw new Error("Proxy has been released and is not useable")}function I(e){return H(e,new Map,{type:"RELEASE"}).then((()=>{P(e)}))}const B=new WeakMap,q="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(B.get(e)||0)-1;B.set(e,t),0===t&&I(e)}));function j(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(Y(s),r===O)return()=>{!function(e){q&&q.unregister(e)}(i),I(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=H(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(J);return o.then.bind(o)}return j(e,t,[...n,r])},set(o,i,r){Y(s);const[a,l]=K(r);return H(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(J)},apply(o,i,r){Y(s);const a=n[n.length-1];if(a===w)return H(e,t,{type:"ENDPOINT"}).then(J);if("bind"===a)return j(e,t,n.slice(0,-1));const[l,d]=W(r);return H(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(J)},construct(o,i){Y(s);const[r,a]=W(i);return H(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(J)}});return function(e,t){const n=(B.get(t)||0)+1;B.set(t,n),q&&q.register(e,t,e)}(i,e),i}function W(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 G=new WeakMap;function K(e){for(const[t,n]of T)if(n.canHandle(e)){const[o,s]=n.serialize(e);return[{type:"HANDLER",name:t,value:o},s]}return[{type:"RAW",value:e},G.get(e)||[]]}function J(e){switch(e.type){case"HANDLER":return T.get(e.name).deserialize(e.value);case"RAW":return e.value}}function H(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",this.coefficientFunctions=null,o("FEAScriptModel instance created")}setSolverConfig(e,t={}){this.solverConfig=e,t&&t.coefficientFunctions&&(this.coefficientFunctions=t.coefficientFunctions,n("Coefficient functions set")),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=[],r=[],a=[];o("Preparing mesh...");const u=function(e){const{meshDimension:t,numElementsX:o,numElementsY:i,maxX:r,maxY:a,elementOrder:u,parsedMesh:c}=e;let m;"1D"===t?m=new l({numElementsX:o,maxX:r,elementOrder:u,parsedMesh:c}):"2D"===t?m=new d({numElementsX:o,maxX:r,numElementsY:i,maxY:a,elementOrder:u,parsedMesh:c}):s("Mesh dimension must be either '1D' or '2D'.");const h=m.boundaryElementsProcessed?m.parsedMesh:m.generateMesh();let f,p,b=h.nodesXCoordinates,y=h.nodesYCoordinates,g=h.totalNodesX,E=h.totalNodesY,v=h.nodalNumbering,M=h.boundaryElements;return null!=c?(f=v.length,p=b.length,n(`Using parsed mesh with ${f} elements and ${p} nodes`)):(f=o*("2D"===t?i:1),p=g*("2D"===t?E:1),n(`Using mesh generated from geometry with ${f} elements and ${p} nodes`)),{nodesXCoordinates:b,nodesYCoordinates:y,totalNodesX:g,totalNodesY:E,nop:v,boundaryElements:M,totalElements:f,totalNodes:p,meshDimension:t,elementOrder:u}}(this.meshConfig);o("Mesh preparation completed");const g={nodesXCoordinates:u.nodesXCoordinates,nodesYCoordinates:u.nodesYCoordinates};if(o("Beginning solving process..."),console.time("totalSolvingTime"),"heatConductionScript"===this.solverConfig)if(o(`Using solver: ${this.solverConfig}`),"frontal"===this.solverMethod){r=$(p,u,this.boundaryConditions).solutionVector}else{({jacobianMatrix:e,residualVector:t}=function(e,t){o("Starting solid heat transfer matrix assembly...");const{nodesXCoordinates:n,nodesYCoordinates:s,nop:i,boundaryElements:r,totalElements:a,meshDimension:l,elementOrder:d}=e,u=c(e),{residualVector:p,jacobianMatrix:b,localToGlobalMap:y,basisFunctions:g,gaussPoints:E,gaussWeights:v,numNodes:M}=u;for(let e=0;e0&&(i.initialSolution=[...r]);const o=A(y,i,100,1e-4);e=o.jacobianMatrix,t=o.residualVector,r=o.solutionVector,n+=1/s}}else if("generalFormPDEScript"===this.solverConfig)if(o(`Using solver: ${this.solverConfig}`),"frontal"===this.solverMethod)s("Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.");else{({jacobianMatrix:e,residualVector:t}=function(e,t,n){o("Starting general form PDE matrix assembly...");const{nodesXCoordinates:i,nodesYCoordinates:r,nop:a,boundaryElements:l,totalElements:d,meshDimension:u,elementOrder:h}=e,{A:f,B:p,C:y,D:g}=n,E=c(e),{residualVector:v,jacobianMatrix:M,localToGlobalMap:C,basisFunctions:D,gaussPoints:$,gaussWeights:F,numNodes:x}=E;if("1D"===u)for(let e=0;e{console.error("FEAScriptWorker: Worker error:",e)};const e=R(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.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},u=0,c=[],m=0,h=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},b=0,y={};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;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);b++,b===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,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,u={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],u,{responsive:!0})}else if("2D"===o&&"contour"===s){const t="structured"===r,o=new Set(a).size,d=new Set(l).size;let u;u=Array.isArray(e[0])?e.map((e=>e[0])):e;let c=Math.min(window.innerWidth,700),m=Math.max(...a),h=Math.max(...l)/m,f=Math.min(c,600),p={title:`${s} plot - ${n}`,width:f,height:f*h*.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]),u=math.transpose(r),c=[];for(let e=0;e | |\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 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/**\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 * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\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 constant temperature boundary conditions for the frontal solver\n * @param {array} nodeConstraintCode - Array indicating boundary condition code for each node\n * @param {array} boundaryValues - Array containing boundary condition values\n */\n imposeConstantTempBoundaryConditionsFront(nodeConstraintCode, boundaryValues) {\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\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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 // 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 * Function to impose convection boundary conditions for the frontal solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @returns {object} An object containing:\n * - localJacobianMatrix: Local Jacobian matrix with convection contributions\n * - localResidualVector: Residual vector with convection contributions\n */\n imposeConvectionBoundaryConditionsFront(\n elementIndex,\n nodesXCoordinates,\n nodesYCoordinates,\n gaussPoints,\n gaussWeights,\n basisFunctions\n ) {\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 // Initialize local Jacobian matrix and local residual vector\n const numNodes = this.nop[elementIndex].length;\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Check if this element is on a convection boundary\n for (const boundaryKey in this.boundaryElements) {\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\n // Find if this element is on this boundary and which side\n const boundaryElement = this.boundaryElements[boundaryKey].find(\n ([elemIdx, _]) => elemIdx === elementIndex\n );\n\n if (boundaryElement) {\n const side = boundaryElement[1];\n\n if (this.meshDimension === \"1D\") {\n // Handle 1D case\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n nodeIndex = side === 0 ? 0 : 1;\n } else if (this.elementOrder === \"quadratic\") {\n nodeIndex = side === 0 ? 0 : 2;\n }\n\n // Add contribution to local Jacobian matrix and local residual vector\n debugLog(\n ` - Applied convection boundary condition to node ${nodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n localResidualVector[nodeIndex] += -convectionCoeff * extTemp;\n localJacobianMatrix[nodeIndex][nodeIndex] += convectionCoeff;\n } else if (this.meshDimension === \"2D\") {\n // Handle 2D case\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n\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 // Get basis functions\n const basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n const basisFunction = basisFunctionsAndDerivatives.basisFunction;\n const basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n const basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n // Calculate tangent vector components\n let ksiDerivX = 0,\n ksiDerivY = 0,\n etaDerivX = 0,\n etaDerivY = 0;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n } else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute tangent vector length\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 // Apply boundary conditions to local matrices\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n localResidualVector[localNodeIndex] +=\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 localJacobianMatrix[localNodeIndex][localNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n // Handle quadratic elements (similar pattern but with more Gauss points)\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n\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 // Apply boundary conditions to local matrices\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n localResidualVector[localNodeIndex] +=\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 localJacobianMatrix[localNodeIndex][localNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n }\n }\n }\n }\n\n return { localJacobianMatrix, localResidualVector };\n }\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 *\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\nexport function assembleHeatConductionMat(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 const 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 const 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 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\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\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 residual vector for the solid heat transfer model when using the frontal system solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nop - Nodal connectivity array (element-to-node mapping)\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @param {object} FEAData - Object containing FEA-related data\n * @returns {object} An object containing:\n * - localJacobianMatrix: Local Jacobian matrix\n * - localResidualVector: Residual vector contributions\n * - ngl: Array mapping local node indices to global node indices\n */\nexport function assembleHeatConductionFront({ elementIndex, nop, meshData, basisFunctions, FEAData }) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n // Loop over Gauss points\n if (meshDimension === \"1D\") {\n // 1D solid heat transfer\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n // 2D solid heat transfer\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } =\n basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1], gaussPoints[gaussPointIndex2]);\n\n // Create mapping from local element space to global mesh (convert to 0-based indexing)\n const localToGlobalMap = ngl.map((globalIndex) => globalIndex - 1);\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\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 return { localJacobianMatrix, localResidualVector, ngl };\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 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 Dirichlet boundary conditions\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n *\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\n imposeDirichletBoundaryConditions(residualVector, jacobianMatrix) {\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 value\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 value\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 value\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 value\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 * Function to impose constant value (Dirichlet) boundary conditions for the frontal solver\n * @param {array} nodeConstraintCode - Array indicating boundary condition code for each node\n * @param {array} boundaryValues - Array containing boundary condition values\n */\n imposeConstantValueBoundaryConditionsFront(nodeConstraintCode, boundaryValues) {\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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// Base viscous term that remains when eikonal equation is fully activated\nconst baseEikonalViscousTerm = 1e-2;\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 let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n debugLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n debugLog(`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 // Unsupported 1D front propagation\n errorLog(\"1D front propagation is not yet supported\");\n\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 // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // TODO 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 eikonalActivationFlag *\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 const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Dirichlet boundary conditions\n genericBoundaryConditions.imposeDirichletBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n\n/**\n * Function to assemble the local Jacobian matrix and residual vector for the front propagation model when using the frontal system solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nop - Nodal connectivity array (element-to-node mapping)\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @param {object} FEAData - Object containing FEA-related data\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 * - localJacobianMatrix: Local Jacobian matrix\n * - residualVector: Residual vector contributions\n * - ngl: Array mapping local node indices to global node indices\n */\nexport function assembleFrontPropagationFront({\n elementIndex,\n nop,\n meshData,\n basisFunctions,\n FEAData,\n solutionVector,\n eikonalActivationFlag,\n}) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n\n // Calculate eikonal viscous term\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(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 // Unsupported 1D front propagation\n errorLog(\"1D front propagation is not yet supported\");\n\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 // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // localJacobianMatrix\n // TODO localJacobianMatrix 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 // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } =\n basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1], gaussPoints[gaussPointIndex2]);\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\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 // Viscous term contribution\n localResidualVector[localNodeIndex1] +=\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 // Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n localResidualVector[localNodeIndex1] +=\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 // Viscous term contribution\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n\n // Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] +=\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 eikonalActivationFlag *\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 return { localJacobianMatrix, localResidualVector, ngl };\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 { initializeFEA } from \"../mesh/meshUtilsScript.js\";\nimport { assembleHeatConductionFront } from \"../solvers/heatConductionScript.js\";\nimport { ThermalBoundaryConditions } from \"../solvers/thermalBoundaryConditionsScript.js\";\nimport { assembleFrontPropagationFront } from \"../solvers/frontPropagationScript.js\";\nimport { GenericBoundaryConditions } from \"../solvers/genericBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// Create object templates\nconst frontalData = {};\nconst frontalState = {};\nconst elementData = { currentElementIndex: 0 };\nconst frontStorage = {};\nlet basisFunctions;\n\n/**\n * Function to run the frontal solver and obtain results for plotting\n * @param {function} assembleFront - Matrix assembler based on the physical model\n * @param {object} meshData - Object containing mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions\n * @param {object} [options] - Additional options for the solver\n * @returns {object} An object containing the solution vector and node coordinates\n */\nexport function runFrontalSolver(assembleFront, meshData, boundaryConditions, options = {}) {\n // Initialize FEA components\n const FEAData = initializeFEA(meshData);\n const totalNodes = meshData.nodesXCoordinates.length;\n const numElements = meshData.totalElements;\n const numNodes = FEAData.numNodes;\n\n // Calculate required array sizes\n initializeFrontalArrays(numNodes, numElements);\n\n // Start timing for system solving (frontal algorithm)\n basicLog(\"Solving system using frontal...\");\n console.time(\"systemSolving\");\n\n // Initialize basis functions\n basisFunctions = new BasisFunctions({\n meshDimension: meshData.meshDimension,\n elementOrder: meshData.elementOrder,\n });\n\n // Copy node connectivity array into frontalData storage\n for (let elementIndex = 0; elementIndex < meshData.totalElements; elementIndex++) {\n for (let nodeIndex = 0; nodeIndex < FEAData.numNodes; nodeIndex++) {\n frontalData.nodalNumbering[elementIndex][nodeIndex] = meshData.nop[elementIndex][nodeIndex];\n }\n }\n\n // Apply Dirichlet-type boundary conditions\n // Initialize all nodes with no boundary condition\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.nodeConstraintCode[nodeIndex] = 0;\n frontalData.boundaryValues[nodeIndex] = 0;\n }\n\n // Handle Dirichlet-type boundary conditions differently based on which solver is being used\n let dirichletBoundaryConditionsHandler;\n // Solid heat transfer model (heatConductionScript solver)\n if (assembleFront === assembleHeatConductionFront) {\n dirichletBoundaryConditionsHandler = new ThermalBoundaryConditions(\n boundaryConditions,\n meshData.boundaryElements,\n meshData.nop,\n meshData.meshDimension,\n meshData.elementOrder\n );\n\n dirichletBoundaryConditionsHandler.imposeConstantTempBoundaryConditionsFront(\n frontalData.nodeConstraintCode,\n frontalData.boundaryValues\n );\n // Front propagation model (frontPropagationScript solver)\n } else if (assembleFront === assembleFrontPropagationFront) {\n dirichletBoundaryConditionsHandler = new GenericBoundaryConditions(\n boundaryConditions,\n meshData.boundaryElements,\n meshData.nop,\n meshData.meshDimension,\n meshData.elementOrder\n );\n\n dirichletBoundaryConditionsHandler.imposeConstantValueBoundaryConditionsFront(\n frontalData.nodeConstraintCode,\n frontalData.boundaryValues\n );\n }\n // Initialize global residual vector\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.globalResidualVector[nodeIndex] = 0;\n }\n\n frontalState.totalNodes = meshData.nodesXCoordinates.length;\n frontalState.writeFlag = 0;\n frontalState.transformationFlag = 1;\n frontalState.determinant = 1;\n\n for (let elementIndex = 0; elementIndex < meshData.totalElements; elementIndex++) {\n frontalState.nodesPerElement[elementIndex] = FEAData.numNodes;\n }\n\n // Parameters for non-linear assemblers\n frontalState.currentSolutionVector = options.solutionVector;\n frontalState.eikonalActivationFlag = options.eikonalActivationFlag;\n\n // Pass assembleFront and dirichletBoundaryConditionsHandler to runFrontalAlgorithm\n runFrontalAlgorithm(meshData, FEAData, dirichletBoundaryConditionsHandler, assembleFront);\n\n // Copy solution\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.solutionVector[nodeIndex] = frontalState.globalSolutionVector[nodeIndex];\n }\n\n // Output results to console for debugging\n const { nodesXCoordinates, nodesYCoordinates } = meshData;\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n if (meshData.meshDimension === \"1D\") {\n // 1D case - only output X coordinates and temperature\n debugLog(\n `${nodesXCoordinates[nodeIndex].toExponential(5)} ${frontalData.solutionVector[\n nodeIndex\n ].toExponential(5)}`\n );\n } else {\n // 2D case - output X, Y coordinates and temperature\n debugLog(\n `${nodesXCoordinates[nodeIndex].toExponential(5)} ${nodesYCoordinates[nodeIndex].toExponential(\n 5\n )} ${frontalData.solutionVector[nodeIndex].toExponential(5)}`\n );\n }\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n const { nodesXCoordinates: finalNodesX, nodesYCoordinates: finalNodesY } = meshData;\n return {\n solutionVector: frontalData.solutionVector.slice(0, totalNodes),\n nodesCoordinates: {\n nodesXCoordinates: finalNodesX,\n nodesYCoordinates: finalNodesY,\n },\n };\n}\n\n/**\n * Function to initialize arrays dynamically based on problem size\n * @param {number} numNodes - Number of nodes per element\n * @param {number} numElements - Number of elements in the mesh\n */\nfunction initializeFrontalArrays(numNodes, numElements) {\n // Use the actual number of elements from the mesh\n frontalData.nodalNumbering = Array(numElements)\n .fill()\n .map(() => Array(numNodes).fill(0));\n frontalData.nodeConstraintCode = Array(numNodes).fill(0);\n frontalData.boundaryValues = Array(numNodes).fill(0);\n frontalData.globalResidualVector = Array(numNodes).fill(0);\n frontalData.solutionVector = Array(numNodes).fill(0);\n frontalData.topologyData = Array(numElements).fill(0);\n frontalData.lateralData = Array(numElements).fill(0);\n\n // Initialize frontalState arrays\n frontalState.writeFlag = 0;\n frontalState.totalNodes = numNodes;\n frontalState.transformationFlag = 0;\n frontalState.nodesPerElement = Array(numElements).fill(0);\n frontalState.determinant = 1;\n\n // For matrix operations, estimate required size based on problem complexity\n const systemSize = Math.max(numNodes, 2000);\n frontalState.globalSolutionVector = Array(systemSize).fill(0);\n frontalState.frontDataIndex = 0;\n\n // Initialize elementData arrays\n elementData.localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n elementData.currentElementIndex = 0;\n\n // Initialize frontStorage arrays\n const frontSize = estimateFrontSize(numNodes, numElements);\n frontStorage.frontValues = Array(frontSize).fill(0);\n frontStorage.columnHeaders = Array(systemSize).fill(0);\n frontStorage.pivotRow = Array(systemSize).fill(0);\n frontStorage.pivotData = Array(frontSize).fill(0);\n}\n\n/**\n * Function to estimate the required front size\n * @param {number} numNodes - Number of of nodes per element\n * @param {number} numElements - Number of elements in the mesh\n * @returns {number} Estimated front size\n */\nfunction estimateFrontSize(numNodes, numElements) {\n const frontWidthEstimate = Math.max(Math.ceil(Math.sqrt(numElements)) * numNodes, numNodes * 2);\n return frontWidthEstimate * numElements;\n}\n// Old function to estimate the required front size\n// function estimateFrontSize(numNodes, numElements, numNodes) {\n// const frontWidthEstimate = Math.ceil(Math.sqrt(numElements) * numNodes * 2);\n// const frontSize = frontWidthEstimate * numNodes * 4;\n// return Math.max(frontSize, 10000);\n// }\n\n/**\n * Function to compute local Jacobian matrix and local residual vector\n * @param {object} meshData - Object containing mesh data\n * @param {object} FEAData - Object containing FEA-related data\n * @param {object} thermalBoundaryConditions - Object containing thermal boundary conditions\n * @param {function} assembleFront - Matrix assembler based on the physical model\n */\nfunction assembleElementContribution(meshData, FEAData, thermalBoundaryConditions, assembleFront) {\n const elementIndex = elementData.currentElementIndex - 1;\n\n // Guard against out-of-range indices\n if (elementIndex < 0 || elementIndex >= meshData.totalElements) {\n errorLog(`Skipping out-of-range elementIndex=${elementIndex} (totalElements=${meshData.totalElements})`);\n return false;\n }\n\n // Domain terms\n const { localJacobianMatrix, localResidualVector, ngl } = assembleFront({\n elementIndex,\n nop: frontalData.nodalNumbering,\n meshData,\n basisFunctions: basisFunctions,\n FEAData,\n // These are ignored by linear assemblers\n solutionVector: frontalState.currentSolutionVector,\n eikonalActivationFlag: frontalState.eikonalActivationFlag,\n });\n\n // Handle Robin-type boundary conditions differently based on which solver is being used\n let boundaryLocalJacobianMatrix = Array(FEAData.numNodes)\n .fill()\n .map(() => Array(FEAData.numNodes).fill(0));\n let boundaryResidualVector = Array(FEAData.numNodes).fill(0);\n\n // heatConductionScript solver\n if (assembleFront === assembleHeatConductionFront) {\n // Check if this element is on a Robin-type boundary\n let isOnRobinTypeBoundary = false;\n for (const boundaryKey in meshData.boundaryElements) {\n if (\n thermalBoundaryConditions.boundaryConditions[boundaryKey]?.[0] === \"convection\" &&\n meshData.boundaryElements[boundaryKey].some(([elemIdx, _]) => elemIdx === elementIndex)\n ) {\n isOnRobinTypeBoundary = true;\n break;\n }\n }\n\n // Only calculate Robin-type for elements when required\n if (isOnRobinTypeBoundary) {\n const { gaussPoints, gaussWeights } = FEAData;\n const result = thermalBoundaryConditions.imposeConvectionBoundaryConditionsFront(\n elementIndex,\n meshData.nodesXCoordinates,\n meshData.nodesYCoordinates,\n gaussPoints,\n gaussWeights,\n basisFunctions\n );\n boundaryLocalJacobianMatrix = result.localJacobianMatrix;\n boundaryResidualVector = result.localResidualVector;\n }\n } else if (assembleFront === assembleFrontPropagationFront) {\n // For now, no Robin-type boundary conditions exist for any other solver\n }\n\n // Combine domain and boundary contributions\n for (let localNodeI = 0; localNodeI < FEAData.numNodes; localNodeI++) {\n for (let localNodeJ = 0; localNodeJ < FEAData.numNodes; localNodeJ++) {\n elementData.localJacobianMatrix[localNodeI][localNodeJ] =\n localJacobianMatrix[localNodeI][localNodeJ] + boundaryLocalJacobianMatrix[localNodeI][localNodeJ];\n }\n }\n\n // Assemble local element residual\n for (let localNodeIndex = 0; localNodeIndex < FEAData.numNodes; localNodeIndex++) {\n const globalNodeIndex = ngl[localNodeIndex] - 1;\n frontalData.globalResidualVector[globalNodeIndex] +=\n localResidualVector[localNodeIndex] + boundaryResidualVector[localNodeIndex];\n }\n\n return true;\n}\n\n/**\n * Function to implement the frontal solver algorithm\n * @param {object} meshData - Object containing mesh data\n * @param {object} FEAData - Object containing FEA-related data\n * @param {object} thermalBoundaryConditions - Object containing thermal boundary conditions\n * @param {function} assembleFront - Matrix assembler based on the physical model\n */\nfunction runFrontalAlgorithm(meshData, FEAData, thermalBoundaryConditions, assembleFront) {\n // Allocate local arrays dynamically\n const totalElements = meshData.totalElements;\n const numNodes = meshData.nodesXCoordinates.length;\n const systemSize = Math.max(numNodes, frontalState.globalSolutionVector.length);\n let localDestination = Array(FEAData.numNodes).fill(0);\n let rowDestination = Array(FEAData.numNodes).fill(0);\n let rowHeaders = Array(systemSize).fill(0);\n let pivotRowIndices = Array(systemSize).fill(0);\n let pivotColumnIndices = Array(systemSize).fill(0);\n let modifiedRows = Array(systemSize).fill(0);\n let pivotColumn = Array(systemSize).fill(0);\n let frontMatrix = Array(systemSize)\n .fill()\n .map(() => Array(systemSize).fill(0));\n let rowSwapCount = Array(numNodes).fill(0);\n let columnSwapCount = Array(numNodes).fill(0);\n let lastAppearanceCheck = Array(numNodes).fill(0);\n let pivotColumnGlobalIndex; // Pivot column global index\n\n let frontDataCounter = 1;\n frontalState.writeFlag++;\n let pivotDataIndex = 1;\n let summedRows = 1;\n elementData.currentElementIndex = 0;\n\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n rowSwapCount[nodeIndex] = 0;\n columnSwapCount[nodeIndex] = 0;\n }\n\n if (frontalState.transformationFlag !== 0) {\n // Prefront: find last appearance of each node\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n lastAppearanceCheck[nodeIndex] = 0;\n }\n\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n let reverseElementIndex = totalElements - elementIndex - 1;\n for (\n let localNodeIndex = 0;\n localNodeIndex < frontalState.nodesPerElement[reverseElementIndex];\n localNodeIndex++\n ) {\n let globalNodeIndex = frontalData.nodalNumbering[reverseElementIndex][localNodeIndex];\n if (lastAppearanceCheck[globalNodeIndex - 1] === 0) {\n lastAppearanceCheck[globalNodeIndex - 1] = 1;\n frontalData.nodalNumbering[reverseElementIndex][localNodeIndex] =\n -frontalData.nodalNumbering[reverseElementIndex][localNodeIndex];\n }\n }\n }\n }\n\n frontalState.transformationFlag = 0;\n let columnCount = 0;\n let rowCount = 0;\n\n for (let i = 0; i < systemSize; i++) {\n for (let j = 0; j < systemSize; j++) {\n frontMatrix[j][i] = 0;\n }\n }\n\n while (true) {\n // Assemble a new element only while we still have elements\n let assembled = false;\n let numElementNodes = 0;\n let numElementColumns = 0;\n\n if (elementData.currentElementIndex < totalElements) {\n elementData.currentElementIndex++;\n assembled = assembleElementContribution(meshData, FEAData, thermalBoundaryConditions, assembleFront);\n }\n\n if (assembled) {\n const currentElement = elementData.currentElementIndex;\n numElementNodes = frontalState.nodesPerElement[currentElement - 1];\n numElementColumns = frontalState.nodesPerElement[currentElement - 1];\n\n for (let localNodeIndex = 0; localNodeIndex < numElementColumns; localNodeIndex++) {\n let globalNodeIndex = frontalData.nodalNumbering[currentElement - 1][localNodeIndex];\n let columnIndex;\n\n if (columnCount === 0) {\n columnCount++;\n localDestination[localNodeIndex] = columnCount;\n frontStorage.columnHeaders[columnCount - 1] = globalNodeIndex;\n } else {\n for (columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n if (Math.abs(globalNodeIndex) === Math.abs(frontStorage.columnHeaders[columnIndex])) break;\n }\n\n if (columnIndex === columnCount) {\n columnCount++;\n localDestination[localNodeIndex] = columnCount;\n frontStorage.columnHeaders[columnCount - 1] = globalNodeIndex;\n } else {\n localDestination[localNodeIndex] = columnIndex + 1;\n frontStorage.columnHeaders[columnIndex] = globalNodeIndex;\n }\n }\n\n let rowIndex;\n if (rowCount === 0) {\n rowCount++;\n rowDestination[localNodeIndex] = rowCount;\n rowHeaders[rowCount - 1] = globalNodeIndex;\n } else {\n for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n if (Math.abs(globalNodeIndex) === Math.abs(rowHeaders[rowIndex])) break;\n }\n\n if (rowIndex === rowCount) {\n rowCount++;\n rowDestination[localNodeIndex] = rowCount;\n rowHeaders[rowCount - 1] = globalNodeIndex;\n } else {\n rowDestination[localNodeIndex] = rowIndex + 1;\n rowHeaders[rowIndex] = globalNodeIndex;\n }\n }\n }\n\n if (rowCount > systemSize || columnCount > systemSize) {\n errorLog(\"Error: systemSize not large enough\");\n return;\n }\n\n for (let localColumnIndex = 0; localColumnIndex < numElementColumns; localColumnIndex++) {\n let frontColumnIndex = localDestination[localColumnIndex];\n for (let localRowIndex = 0; localRowIndex < numElementNodes; localRowIndex++) {\n let frontRowIndex = rowDestination[localRowIndex];\n frontMatrix[frontRowIndex - 1][frontColumnIndex - 1] +=\n elementData.localJacobianMatrix[localRowIndex][localColumnIndex];\n }\n }\n }\n\n // Pivoting/elimination continues whether or not a new element was assembled\n let availableColumnCount = 0;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n if (frontStorage.columnHeaders[columnIndex] < 0) {\n pivotColumnIndices[availableColumnCount] = columnIndex + 1;\n availableColumnCount++;\n }\n }\n\n let constrainedRowCount = 0;\n let availableRowCount = 0;\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n let globalNodeIndex = rowHeaders[rowIndex];\n if (globalNodeIndex < 0) {\n pivotRowIndices[availableRowCount] = rowIndex + 1;\n availableRowCount++;\n let absoluteNodeIndex = Math.abs(globalNodeIndex);\n if (frontalData.nodeConstraintCode[absoluteNodeIndex - 1] === 1) {\n modifiedRows[constrainedRowCount] = rowIndex + 1;\n constrainedRowCount++;\n frontalData.nodeConstraintCode[absoluteNodeIndex - 1] = 2;\n frontalData.globalResidualVector[absoluteNodeIndex - 1] =\n frontalData.boundaryValues[absoluteNodeIndex - 1];\n }\n }\n }\n\n if (constrainedRowCount > 0) {\n for (let constrainedIndex = 0; constrainedIndex < constrainedRowCount; constrainedIndex++) {\n let rowIndex = modifiedRows[constrainedIndex] - 1;\n let globalNodeIndex = Math.abs(rowHeaders[rowIndex]);\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex][columnIndex] = 0;\n let columnGlobalIndex = Math.abs(frontStorage.columnHeaders[columnIndex]);\n if (columnGlobalIndex === globalNodeIndex) frontMatrix[rowIndex][columnIndex] = 1;\n }\n }\n }\n\n if (availableColumnCount > summedRows || elementData.currentElementIndex < totalElements) {\n if (availableColumnCount === 0) {\n errorLog(\"Error: no more rows fully summed\");\n return;\n }\n\n let pivotRowIndex = pivotRowIndices[0];\n let pivotColumnIndex = pivotColumnIndices[0];\n let pivotValue = frontMatrix[pivotRowIndex - 1][pivotColumnIndex - 1];\n\n if (Math.abs(pivotValue) < 1e-4) {\n pivotValue = 0;\n for (let columnIndex = 0; columnIndex < availableColumnCount; columnIndex++) {\n let testColumnIndex = pivotColumnIndices[columnIndex];\n for (let rowIndex = 0; rowIndex < availableRowCount; rowIndex++) {\n let testRowIndex = pivotRowIndices[rowIndex];\n let testValue = frontMatrix[testRowIndex - 1][testColumnIndex - 1];\n if (Math.abs(testValue) > Math.abs(pivotValue)) {\n pivotValue = testValue;\n pivotColumnIndex = testColumnIndex;\n pivotRowIndex = testRowIndex;\n }\n }\n }\n }\n\n let pivotGlobalRowIndex = Math.abs(rowHeaders[pivotRowIndex - 1]);\n pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[pivotColumnIndex - 1]); // Assign, don't declare\n let permutationHelper =\n pivotGlobalRowIndex +\n pivotColumnGlobalIndex +\n rowSwapCount[pivotGlobalRowIndex - 1] +\n columnSwapCount[pivotColumnGlobalIndex - 1];\n frontalState.determinant =\n (frontalState.determinant * pivotValue * (-1) ** permutationHelper) / Math.abs(pivotValue);\n\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n if (nodeIndex >= pivotGlobalRowIndex) rowSwapCount[nodeIndex]--;\n if (nodeIndex >= pivotColumnGlobalIndex) columnSwapCount[nodeIndex]--;\n }\n\n if (Math.abs(pivotValue) < 1e-10) {\n errorLog(\n `Matrix singular or ill-conditioned, currentElementIndex=${elementData.currentElementIndex}, pivotGlobalRowIndex=${pivotGlobalRowIndex}, pivotColumnGlobalIndex=${pivotColumnGlobalIndex}, pivotValue=${pivotValue}`\n );\n }\n\n if (pivotValue === 0) return;\n\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.pivotRow[columnIndex] = frontMatrix[pivotRowIndex - 1][columnIndex] / pivotValue;\n }\n\n let rightHandSide = frontalData.globalResidualVector[pivotGlobalRowIndex - 1] / pivotValue;\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] = rightHandSide;\n pivotColumn[pivotRowIndex - 1] = pivotValue;\n\n if (pivotRowIndex > 1) {\n for (let rowIndex = 0; rowIndex < pivotRowIndex - 1; rowIndex++) {\n let globalRowIndex = Math.abs(rowHeaders[rowIndex]);\n let eliminationFactor = frontMatrix[rowIndex][pivotColumnIndex - 1];\n pivotColumn[rowIndex] = eliminationFactor;\n if (pivotColumnIndex > 1 && eliminationFactor !== 0) {\n for (let columnIndex = 0; columnIndex < pivotColumnIndex - 1; columnIndex++) {\n frontMatrix[rowIndex][columnIndex] -= eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n if (pivotColumnIndex < columnCount) {\n for (let columnIndex = pivotColumnIndex; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex][columnIndex - 1] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n frontalData.globalResidualVector[globalRowIndex - 1] -= eliminationFactor * rightHandSide;\n }\n }\n\n if (pivotRowIndex < rowCount) {\n for (let rowIndex = pivotRowIndex; rowIndex < rowCount; rowIndex++) {\n let globalRowIndex = Math.abs(rowHeaders[rowIndex]);\n let eliminationFactor = frontMatrix[rowIndex][pivotColumnIndex - 1];\n pivotColumn[rowIndex] = eliminationFactor;\n if (pivotColumnIndex > 1) {\n for (let columnIndex = 0; columnIndex < pivotColumnIndex - 1; columnIndex++) {\n frontMatrix[rowIndex - 1][columnIndex] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n if (pivotColumnIndex < columnCount) {\n for (let columnIndex = pivotColumnIndex; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex - 1][columnIndex - 1] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n frontalData.globalResidualVector[globalRowIndex - 1] -= eliminationFactor * rightHandSide;\n }\n }\n\n for (let i = 0; i < rowCount; i++) {\n frontStorage.pivotData[pivotDataIndex + i - 1] = pivotColumn[i];\n }\n pivotDataIndex += rowCount;\n\n for (let i = 0; i < rowCount; i++) {\n frontStorage.pivotData[pivotDataIndex + i - 1] = rowHeaders[i];\n }\n pivotDataIndex += rowCount;\n\n frontStorage.pivotData[pivotDataIndex - 1] = pivotRowIndex;\n pivotDataIndex++;\n\n for (let i = 0; i < columnCount; i++) {\n frontStorage.frontValues[frontDataCounter - 1 + i] = frontStorage.pivotRow[i];\n }\n frontDataCounter += columnCount;\n\n for (let i = 0; i < columnCount; i++) {\n frontStorage.frontValues[frontDataCounter - 1 + i] = frontStorage.columnHeaders[i];\n }\n frontDataCounter += columnCount;\n\n frontStorage.frontValues[frontDataCounter - 1] = pivotGlobalRowIndex;\n frontStorage.frontValues[frontDataCounter] = columnCount;\n frontStorage.frontValues[frontDataCounter + 1] = pivotColumnIndex;\n frontStorage.frontValues[frontDataCounter + 2] = pivotValue;\n frontDataCounter += 4;\n\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n frontMatrix[rowIndex][columnCount - 1] = 0;\n }\n\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowCount - 1][columnIndex] = 0;\n }\n\n columnCount--;\n if (pivotColumnIndex < columnCount + 1) {\n for (let columnIndex = pivotColumnIndex - 1; columnIndex < columnCount; columnIndex++) {\n frontStorage.columnHeaders[columnIndex] = frontStorage.columnHeaders[columnIndex + 1];\n }\n }\n\n rowCount--;\n if (pivotRowIndex < rowCount + 1) {\n for (let rowIndex = pivotRowIndex - 1; rowIndex < rowCount; rowIndex++) {\n rowHeaders[rowIndex] = rowHeaders[rowIndex + 1];\n }\n }\n\n if (rowCount > 1 || elementData.currentElementIndex < totalElements) continue;\n\n pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[0]); // Assign, don't declare\n pivotRowIndex = 1;\n pivotValue = frontMatrix[0][0];\n pivotGlobalRowIndex = Math.abs(rowHeaders[0]);\n pivotColumnIndex = 1;\n permutationHelper =\n pivotGlobalRowIndex +\n pivotColumnGlobalIndex +\n rowSwapCount[pivotGlobalRowIndex - 1] +\n columnSwapCount[pivotColumnGlobalIndex - 1];\n frontalState.determinant =\n (frontalState.determinant * pivotValue * (-1) ** permutationHelper) / Math.abs(pivotValue);\n\n frontStorage.pivotRow[0] = 1;\n if (Math.abs(pivotValue) < 1e-10) {\n errorLog(\n `Matrix singular or ill-conditioned, currentElementIndex=${elementData.currentElementIndex}, pivotGlobalRowIndex=${pivotGlobalRowIndex}, pivotColumnGlobalIndex=${pivotColumnGlobalIndex}, pivotValue=${pivotValue}`\n );\n }\n\n if (pivotValue === 0) return;\n\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] =\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] / pivotValue;\n frontStorage.frontValues[frontDataCounter - 1] = frontStorage.pivotRow[0];\n frontDataCounter++;\n frontStorage.frontValues[frontDataCounter - 1] = frontStorage.columnHeaders[0];\n frontDataCounter++;\n frontStorage.frontValues[frontDataCounter - 1] = pivotGlobalRowIndex;\n frontStorage.frontValues[frontDataCounter] = columnCount;\n frontStorage.frontValues[frontDataCounter + 1] = pivotColumnIndex;\n frontStorage.frontValues[frontDataCounter + 2] = pivotValue;\n frontDataCounter += 4;\n\n frontStorage.pivotData[pivotDataIndex - 1] = pivotColumn[0];\n pivotDataIndex++;\n frontStorage.pivotData[pivotDataIndex - 1] = rowHeaders[0];\n pivotDataIndex++;\n frontStorage.pivotData[pivotDataIndex - 1] = pivotRowIndex;\n pivotDataIndex++;\n\n frontalState.frontDataIndex = frontDataCounter;\n if (frontalState.writeFlag === 1)\n debugLog(`total ecs transfer in matrix reduction=${frontDataCounter}`);\n\n // Back substitution\n performBackSubstitution(frontDataCounter);\n break;\n }\n }\n}\n\n/**\n * Function to perform back substitution for the frontal solver\n * @param {number} frontDataCounter - Index counter for the element contributions\n */\nfunction performBackSubstitution(frontDataCounter) {\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n frontalState.globalSolutionVector[nodeIndex] = frontalData.boundaryValues[nodeIndex];\n }\n\n for (let iterationIndex = 1; iterationIndex <= frontalState.totalNodes; iterationIndex++) {\n frontDataCounter -= 4;\n let pivotGlobalRowIndex = frontStorage.frontValues[frontDataCounter - 1];\n let columnCount = frontStorage.frontValues[frontDataCounter];\n let pivotColumnIndex = frontStorage.frontValues[frontDataCounter + 1];\n let pivotValue = frontStorage.frontValues[frontDataCounter + 2];\n\n if (iterationIndex === 1) {\n frontDataCounter--;\n frontStorage.columnHeaders[0] = frontStorage.frontValues[frontDataCounter - 1];\n frontDataCounter--;\n frontStorage.pivotRow[0] = frontStorage.frontValues[frontDataCounter - 1];\n } else {\n frontDataCounter -= columnCount;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.columnHeaders[columnIndex] =\n frontStorage.frontValues[frontDataCounter - 1 + columnIndex];\n }\n frontDataCounter -= columnCount;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.pivotRow[columnIndex] = frontStorage.frontValues[frontDataCounter - 1 + columnIndex];\n }\n }\n\n let pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[pivotColumnIndex - 1]);\n if (frontalData.nodeConstraintCode[pivotColumnGlobalIndex - 1] > 0) continue;\n\n let accumulatedValue = 0;\n frontStorage.pivotRow[pivotColumnIndex - 1] = 0;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n accumulatedValue -=\n frontStorage.pivotRow[columnIndex] *\n frontalState.globalSolutionVector[Math.abs(frontStorage.columnHeaders[columnIndex]) - 1];\n }\n\n frontalState.globalSolutionVector[pivotColumnGlobalIndex - 1] =\n accumulatedValue + frontalData.globalResidualVector[pivotGlobalRowIndex - 1];\n\n frontalData.nodeConstraintCode[pivotColumnGlobalIndex - 1] = 1;\n }\n\n if (frontalState.writeFlag === 1)\n debugLog(`value of frontDataCounter after backsubstitution=${frontDataCounter}`);\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 { runFrontalSolver } from \"./frontalSolverScript.js\";\nimport { assembleFrontPropagationFront } from \"../solvers/frontPropagationScript.js\";\n\n/**\n * Function to solve a system of non-linear equations using the Newton-Raphson method\n * @param {function} assembleMat - Matrix assembler based on the physical model\n * @param {object} context - Context object containing simulation data and options\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\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 // Check if using frontal solver\n if (context.solverMethod === \"frontal\") {\n const frontalResult = runFrontalSolver(\n assembleFrontPropagationFront,\n context.meshData,\n context.boundaryConditions,\n { solutionVector, eikonalActivationFlag: context.eikonalActivationFlag }\n );\n deltaX = frontalResult.solutionVector;\n } else {\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\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 * @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 { assembleGeneralFormPDEMat, assembleGeneralFormPDEFront } from \"./solvers/generalFormPDEScript.js\";\nimport { assembleHeatConductionMat, assembleHeatConductionFront } from \"./solvers/heatConductionScript.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 this.coefficientFunctions = null; // Add storage for coefficient functions\n basicLog(\"FEAScriptModel instance created\");\n }\n\n /**\n * Sets the solver configuration\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} [options] - Optional additional configuration\n */\n setSolverConfig(solverConfig, options = {}) {\n this.solverConfig = solverConfig;\n\n // Store coefficient functions if provided\n if (options && options.coefficientFunctions) {\n this.coefficientFunctions = options.coefficientFunctions;\n debugLog(\"Coefficient functions set\");\n }\n\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 /**\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\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 === \"heatConductionScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Check if using frontal solver\n if (this.solverMethod === \"frontal\") {\n const frontalResult = runFrontalSolver(\n assembleHeatConductionFront,\n meshData,\n this.boundaryConditions\n );\n solutionVector = frontalResult.solutionVector;\n } else {\n // Use regular linear solver methods\n ({ jacobianMatrix, residualVector } = assembleHeatConductionMat(meshData, this.boundaryConditions));\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 } else if (this.solverConfig === \"generalFormPDEScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n // Check if using frontal solver\n if (this.solverMethod === \"frontal\") {\n errorLog(\n \"Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.\"\n );\n } else {\n // Use regular linear solver methods\n ({ jacobianMatrix, residualVector } = assembleGeneralFormPDEMat(\n meshData,\n this.boundaryConditions,\n this.coefficientFunctions\n ));\n\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\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 { initializeFEA, performIsoparametricMapping1D } from \"../mesh/meshUtilsScript.js\";\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the Jacobian matrix and residuals vector for the general form PDE model\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions\n * @param {object} coefficientFunctions - Functions A(x), B(x), C(x), D(x) for the PDE\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n */\nexport function assembleGeneralFormPDEMat(meshData, boundaryConditions, coefficientFunctions) {\n basicLog(\"Starting general form PDE 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 // Extract coefficient functions\n const { A, B, C, D } = coefficientFunctions;\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 if (meshDimension === \"1D\") {\n // 1D general form PDE\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 // Convert to 0-based indexing\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex = 0; gaussPointIndex < gaussPoints.length; gaussPointIndex++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < numNodes; i++) {\n xCoord += nodesXCoordinates[localToGlobalMap[i]] * basisFunction[i];\n }\n\n // Evaluate coefficient functions at this physical coordinate\n const a = A(xCoord);\n const b = B(xCoord);\n const c = C(xCoord);\n const d = D(xCoord);\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n const globalNodeIndex1 = localToGlobalMap[localNodeIndex1];\n\n // Source term contribution to residual vector\n residualVector[globalNodeIndex1] -=\n gaussWeights[gaussPointIndex] * detJacobian * d * basisFunction[localNodeIndex1];\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n const globalNodeIndex2 = localToGlobalMap[localNodeIndex2];\n\n // Diffusion term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n a *\n basisFunctionDerivX[localNodeIndex1] *\n basisFunctionDerivX[localNodeIndex2];\n\n // Advection term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n b *\n basisFunctionDerivX[localNodeIndex2] *\n basisFunction[localNodeIndex1];\n\n // Reaction term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n c *\n basisFunction[localNodeIndex1] *\n basisFunction[localNodeIndex2];\n }\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n errorLog(\"2D general form PDE is not yet supported in assembleGeneralFormPDEMat.\");\n // 2D general form PDE - empty for now\n }\n\n // Apply boundary conditions\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Apply Dirichlet boundary conditions only\n genericBoundaryConditions.imposeDirichletBoundaryConditions(residualVector, jacobianMatrix);\n\n basicLog(\"General form PDE matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n\n/**\n * Function to assemble the frontal solver matrix for the general form PDE model\n * @param {object} data - Object containing element data for the frontal solver\n * @returns {object} An object containing local Jacobian matrix and residual vector\n */\nexport function assembleGeneralFormPDEFront({\n elementIndex,\n nop,\n meshData,\n basisFunctions,\n FEAData,\n coefficientFunctions,\n}) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n const { A, B, C, D } = coefficientFunctions;\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n if (meshDimension === \"1D\") {\n // 1D general form PDE\n\n // Loop over Gauss points\n for (let gaussPointIndex = 0; gaussPointIndex < gaussPoints.length; gaussPointIndex++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < numNodes; i++) {\n xCoord += nodesXCoordinates[localToGlobalMap[i]] * basisFunction[i];\n }\n\n // Evaluate coefficient functions at this physical coordinate\n const a = A(xCoord);\n const b = B(xCoord);\n const c = C(xCoord);\n const d = D(xCoord);\n\n // Computation of local Jacobian matrix and residual vector\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n // Source term contribution to local residual vector\n localResidualVector[localNodeIndex1] -=\n gaussWeights[gaussPointIndex] * detJacobian * d * basisFunction[localNodeIndex1];\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n // Diffusion term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n a *\n basisFunctionDerivX[localNodeIndex1] *\n basisFunctionDerivX[localNodeIndex2];\n\n // Advection term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n b *\n basisFunctionDerivX[localNodeIndex2] *\n basisFunction[localNodeIndex1];\n\n // Reaction term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n c *\n basisFunction[localNodeIndex1] *\n basisFunction[localNodeIndex2];\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n errorLog(\"2D general form PDE is not yet supported in assembleGeneralFormPDEFront.\");\n // 2D general form PDE - empty for now\n }\n\n return {\n localJacobianMatrix,\n localResidualVector,\n ngl,\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\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// | ____| ____| /\\ / ____| (_) | | //\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 } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const printVersion = \"0.1.3\";"],"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","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","nodesXCoordinates","totalNodesX","deltaX","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","meshData","totalNodes","colIndex","basisFunctions","gaussPointsAndWeights","localToGlobalMap","numNodes","performIsoparametricMapping1D","params","xCoordinates","ksiDerivX","localNodeIndex","detJacobian","basisFunctionDerivX","performIsoparametricMapping2D","yCoordinates","etaDerivX","ksiDerivY","etaDerivY","basisFunctionDerivY","ThermalBoundaryConditions","boundaryConditions","imposeConstantTempBoundaryConditions","Object","keys","boundaryKey","tempValue","globalNodeIndex","imposeConstantTempBoundaryConditionsFront","nodeConstraintCode","boundaryValues","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","basisFunctionsAndDerivatives","tangentVectorLength","localNodeIndex2","globalNodeIndex2","gaussPointIndex","imposeConvectionBoundaryConditionsFront","localJacobianMatrix","map","localResidualVector","boundaryElement","find","_","assembleHeatConductionFront","FEAData","ngl","gaussPointIndex1","localNodeIndex1","gaussPointIndex2","globalIndex","GenericBoundaryConditions","imposeDirichletBoundaryConditions","value","imposeConstantValueBoundaryConditionsFront","assembleFrontPropagationMat","eikonalActivationFlag","eikonalViscousTerm","totalElements","mappingResult","solutionDerivX","solutionDerivY","localToGlobalMap1","localToGlobalMap2","assembleFrontPropagationFront","frontalData","frontalState","elementData","currentElementIndex","frontStorage","runFrontalSolver","assembleFront","numElements","globalResidualVector","topologyData","lateralData","writeFlag","transformationFlag","nodesPerElement","determinant","systemSize","globalSolutionVector","frontDataIndex","frontSize","frontWidthEstimate","ceil","estimateFrontSize","frontValues","columnHeaders","pivotRow","pivotData","initializeFrontalArrays","dirichletBoundaryConditionsHandler","currentSolutionVector","thermalBoundaryConditions","pivotColumnGlobalIndex","localDestination","rowDestination","rowHeaders","pivotRowIndices","pivotColumnIndices","modifiedRows","pivotColumn","frontMatrix","rowSwapCount","columnSwapCount","lastAppearanceCheck","frontDataCounter","pivotDataIndex","summedRows","reverseElementIndex","columnCount","rowCount","assembled","numElementNodes","numElementColumns","assembleElementContribution","currentElement","columnIndex","rowIndex","localColumnIndex","frontColumnIndex","localRowIndex","availableColumnCount","constrainedRowCount","availableRowCount","absoluteNodeIndex","constrainedIndex","pivotRowIndex","pivotColumnIndex","pivotValue","testColumnIndex","testRowIndex","testValue","pivotGlobalRowIndex","permutationHelper","rightHandSide","globalRowIndex","eliminationFactor","performBackSubstitution","runFrontalAlgorithm","toExponential","finalNodesX","finalNodesY","slice","nodesCoordinates","boundaryLocalJacobianMatrix","boundaryResidualVector","isOnRobinTypeBoundary","some","result","localNodeI","localNodeJ","iterationIndex","accumulatedValue","newtonRaphson","assembleMat","context","errorNorm","initialSolution","Number","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","meshConfig","coefficientFunctions","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","mesh","nodesCoordinatesAndNumbering","prepareMesh","assembleHeatConductionMat","eikonalExteralIterations","newtonRaphsonResult","A","B","C","D","xCoord","a","b","d","globalNodeIndex1","assembleGeneralFormPDEMat","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","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","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","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"],"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/mesh/basisFunctionsScript.js","../src/mesh/meshGenerationScript.js","../src/methods/numericalIntegrationScript.js","../src/mesh/meshUtilsScript.js","../src/solvers/thermalBoundaryConditionsScript.js","../src/solvers/heatConductionScript.js","../src/solvers/genericBoundaryConditionsScript.js","../src/solvers/frontPropagationScript.js","../src/methods/frontalSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/vendor/comlink.mjs","../src/FEAScript.js","../src/solvers/generalFormPDEScript.js","../src/workers/workerScript.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.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 printVersionInformation() {\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 errorLog(`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 { 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 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/**\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 * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\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 constant temperature boundary conditions for the frontal solver\n * @param {array} nodeConstraintCode - Array indicating boundary condition code for each node\n * @param {array} boundaryValues - Array containing boundary condition values\n */\n imposeConstantTempBoundaryConditionsFront(nodeConstraintCode, boundaryValues) {\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\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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 // 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 * Function to impose convection boundary conditions for the frontal solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @returns {object} An object containing:\n * - localJacobianMatrix: Local Jacobian matrix with convection contributions\n * - localResidualVector: Residual vector with convection contributions\n */\n imposeConvectionBoundaryConditionsFront(\n elementIndex,\n nodesXCoordinates,\n nodesYCoordinates,\n gaussPoints,\n gaussWeights,\n basisFunctions\n ) {\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 // Initialize local Jacobian matrix and local residual vector\n const numNodes = this.nop[elementIndex].length;\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Check if this element is on a convection boundary\n for (const boundaryKey in this.boundaryElements) {\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\n // Find if this element is on this boundary and which side\n const boundaryElement = this.boundaryElements[boundaryKey].find(\n ([elemIdx, _]) => elemIdx === elementIndex\n );\n\n if (boundaryElement) {\n const side = boundaryElement[1];\n\n if (this.meshDimension === \"1D\") {\n // Handle 1D case\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n nodeIndex = side === 0 ? 0 : 1;\n } else if (this.elementOrder === \"quadratic\") {\n nodeIndex = side === 0 ? 0 : 2;\n }\n\n // Add contribution to local Jacobian matrix and local residual vector\n debugLog(\n ` - Applied convection boundary condition to node ${nodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n localResidualVector[nodeIndex] += -convectionCoeff * extTemp;\n localJacobianMatrix[nodeIndex][nodeIndex] += convectionCoeff;\n } else if (this.meshDimension === \"2D\") {\n // Handle 2D case\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n\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 // Get basis functions\n const basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n const basisFunction = basisFunctionsAndDerivatives.basisFunction;\n const basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n const basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n // Calculate tangent vector components\n let ksiDerivX = 0,\n ksiDerivY = 0,\n etaDerivX = 0,\n etaDerivY = 0;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n } else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute tangent vector length\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 // Apply boundary conditions to local matrices\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n localResidualVector[localNodeIndex] +=\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 localJacobianMatrix[localNodeIndex][localNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n // Handle quadratic elements (similar pattern but with more Gauss points)\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n\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 // Apply boundary conditions to local matrices\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n localResidualVector[localNodeIndex] +=\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 localJacobianMatrix[localNodeIndex][localNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n }\n }\n }\n }\n\n return { localJacobianMatrix, localResidualVector };\n }\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 *\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\nexport function assembleHeatConductionMat(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 const 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 const 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 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\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\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 residual vector for the solid heat transfer model when using the frontal system solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nop - Nodal connectivity array (element-to-node mapping)\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @param {object} FEAData - Object containing FEA-related data\n * @returns {object} An object containing:\n * - localJacobianMatrix: Local Jacobian matrix\n * - localResidualVector: Residual vector contributions\n * - ngl: Array mapping local node indices to global node indices\n */\nexport function assembleHeatConductionFront({ elementIndex, nop, meshData, basisFunctions, FEAData }) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n // Loop over Gauss points\n if (meshDimension === \"1D\") {\n // 1D solid heat transfer\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n // 2D solid heat transfer\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } =\n basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1], gaussPoints[gaussPointIndex2]);\n\n // Create mapping from local element space to global mesh (convert to 0-based indexing)\n const localToGlobalMap = ngl.map((globalIndex) => globalIndex - 1);\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\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 return { localJacobianMatrix, localResidualVector, ngl };\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 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 Dirichlet boundary conditions\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n *\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\n imposeDirichletBoundaryConditions(residualVector, jacobianMatrix) {\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 value\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 value\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 value\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 value\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 * Function to impose constant value (Dirichlet) boundary conditions for the frontal solver\n * @param {array} nodeConstraintCode - Array indicating boundary condition code for each node\n * @param {array} boundaryValues - Array containing boundary condition values\n */\n imposeConstantValueBoundaryConditionsFront(nodeConstraintCode, boundaryValues) {\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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// Base viscous term that remains when eikonal equation is fully activated\nconst baseEikonalViscousTerm = 1e-2;\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 let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n debugLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n debugLog(`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 // Unsupported 1D front propagation\n errorLog(\"1D front propagation is not yet supported\");\n\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 // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // TODO 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 eikonalActivationFlag *\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 const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Dirichlet boundary conditions\n genericBoundaryConditions.imposeDirichletBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n\n/**\n * Function to assemble the local Jacobian matrix and residual vector for the front propagation model when using the frontal system solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nop - Nodal connectivity array (element-to-node mapping)\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @param {object} FEAData - Object containing FEA-related data\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 * - localJacobianMatrix: Local Jacobian matrix\n * - residualVector: Residual vector contributions\n * - ngl: Array mapping local node indices to global node indices\n */\nexport function assembleFrontPropagationFront({\n elementIndex,\n nop,\n meshData,\n basisFunctions,\n FEAData,\n solutionVector,\n eikonalActivationFlag,\n}) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n\n // Calculate eikonal viscous term\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(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 // Unsupported 1D front propagation\n errorLog(\"1D front propagation is not yet supported\");\n\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 // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // localJacobianMatrix\n // TODO localJacobianMatrix 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 // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } =\n basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1], gaussPoints[gaussPointIndex2]);\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\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 // Viscous term contribution\n localResidualVector[localNodeIndex1] +=\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 // Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n localResidualVector[localNodeIndex1] +=\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 // Viscous term contribution\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n\n // Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] +=\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 eikonalActivationFlag *\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 return { localJacobianMatrix, localResidualVector, ngl };\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 { initializeFEA } from \"../mesh/meshUtilsScript.js\";\nimport { assembleHeatConductionFront } from \"../solvers/heatConductionScript.js\";\nimport { ThermalBoundaryConditions } from \"../solvers/thermalBoundaryConditionsScript.js\";\nimport { assembleFrontPropagationFront } from \"../solvers/frontPropagationScript.js\";\nimport { GenericBoundaryConditions } from \"../solvers/genericBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// Create object templates\nconst frontalData = {};\nconst frontalState = {};\nconst elementData = { currentElementIndex: 0 };\nconst frontStorage = {};\nlet basisFunctions;\n\n/**\n * Function to run the frontal solver and obtain results for plotting\n * @param {function} assembleFront - Matrix assembler based on the physical model\n * @param {object} meshData - Object containing mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions\n * @param {object} [options] - Additional options for the solver\n * @returns {object} An object containing the solution vector and node coordinates\n */\nexport function runFrontalSolver(assembleFront, meshData, boundaryConditions, options = {}) {\n // Initialize FEA components\n const FEAData = initializeFEA(meshData);\n const totalNodes = meshData.nodesXCoordinates.length;\n const numElements = meshData.totalElements;\n const numNodes = FEAData.numNodes;\n\n // Calculate required array sizes\n initializeFrontalArrays(numNodes, numElements);\n\n // Start timing for system solving (frontal algorithm)\n basicLog(\"Solving system using frontal...\");\n console.time(\"systemSolving\");\n\n // Initialize basis functions\n basisFunctions = new BasisFunctions({\n meshDimension: meshData.meshDimension,\n elementOrder: meshData.elementOrder,\n });\n\n // Copy node connectivity array into frontalData storage\n for (let elementIndex = 0; elementIndex < meshData.totalElements; elementIndex++) {\n for (let nodeIndex = 0; nodeIndex < FEAData.numNodes; nodeIndex++) {\n frontalData.nodalNumbering[elementIndex][nodeIndex] = meshData.nop[elementIndex][nodeIndex];\n }\n }\n\n // Apply Dirichlet-type boundary conditions\n // Initialize all nodes with no boundary condition\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.nodeConstraintCode[nodeIndex] = 0;\n frontalData.boundaryValues[nodeIndex] = 0;\n }\n\n // Handle Dirichlet-type boundary conditions differently based on which solver is being used\n let dirichletBoundaryConditionsHandler;\n // Solid heat transfer model (heatConductionScript solver)\n if (assembleFront === assembleHeatConductionFront) {\n dirichletBoundaryConditionsHandler = new ThermalBoundaryConditions(\n boundaryConditions,\n meshData.boundaryElements,\n meshData.nop,\n meshData.meshDimension,\n meshData.elementOrder\n );\n\n dirichletBoundaryConditionsHandler.imposeConstantTempBoundaryConditionsFront(\n frontalData.nodeConstraintCode,\n frontalData.boundaryValues\n );\n // Front propagation model (frontPropagationScript solver)\n } else if (assembleFront === assembleFrontPropagationFront) {\n dirichletBoundaryConditionsHandler = new GenericBoundaryConditions(\n boundaryConditions,\n meshData.boundaryElements,\n meshData.nop,\n meshData.meshDimension,\n meshData.elementOrder\n );\n\n dirichletBoundaryConditionsHandler.imposeConstantValueBoundaryConditionsFront(\n frontalData.nodeConstraintCode,\n frontalData.boundaryValues\n );\n }\n // Initialize global residual vector\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.globalResidualVector[nodeIndex] = 0;\n }\n\n frontalState.totalNodes = meshData.nodesXCoordinates.length;\n frontalState.writeFlag = 0;\n frontalState.transformationFlag = 1;\n frontalState.determinant = 1;\n\n for (let elementIndex = 0; elementIndex < meshData.totalElements; elementIndex++) {\n frontalState.nodesPerElement[elementIndex] = FEAData.numNodes;\n }\n\n // Parameters for non-linear assemblers\n frontalState.currentSolutionVector = options.solutionVector;\n frontalState.eikonalActivationFlag = options.eikonalActivationFlag;\n\n // Pass assembleFront and dirichletBoundaryConditionsHandler to runFrontalAlgorithm\n runFrontalAlgorithm(meshData, FEAData, dirichletBoundaryConditionsHandler, assembleFront);\n\n // Copy solution\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.solutionVector[nodeIndex] = frontalState.globalSolutionVector[nodeIndex];\n }\n\n // Output results to console for debugging\n const { nodesXCoordinates, nodesYCoordinates } = meshData;\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n if (meshData.meshDimension === \"1D\") {\n // 1D case - only output X coordinates and temperature\n debugLog(\n `${nodesXCoordinates[nodeIndex].toExponential(5)} ${frontalData.solutionVector[\n nodeIndex\n ].toExponential(5)}`\n );\n } else {\n // 2D case - output X, Y coordinates and temperature\n debugLog(\n `${nodesXCoordinates[nodeIndex].toExponential(5)} ${nodesYCoordinates[nodeIndex].toExponential(\n 5\n )} ${frontalData.solutionVector[nodeIndex].toExponential(5)}`\n );\n }\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n const { nodesXCoordinates: finalNodesX, nodesYCoordinates: finalNodesY } = meshData;\n return {\n solutionVector: frontalData.solutionVector.slice(0, totalNodes),\n nodesCoordinates: {\n nodesXCoordinates: finalNodesX,\n nodesYCoordinates: finalNodesY,\n },\n };\n}\n\n/**\n * Function to initialize arrays dynamically based on problem size\n * @param {number} numNodes - Number of nodes per element\n * @param {number} numElements - Number of elements in the mesh\n */\nfunction initializeFrontalArrays(numNodes, numElements) {\n // Use the actual number of elements from the mesh\n frontalData.nodalNumbering = Array(numElements)\n .fill()\n .map(() => Array(numNodes).fill(0));\n frontalData.nodeConstraintCode = Array(numNodes).fill(0);\n frontalData.boundaryValues = Array(numNodes).fill(0);\n frontalData.globalResidualVector = Array(numNodes).fill(0);\n frontalData.solutionVector = Array(numNodes).fill(0);\n frontalData.topologyData = Array(numElements).fill(0);\n frontalData.lateralData = Array(numElements).fill(0);\n\n // Initialize frontalState arrays\n frontalState.writeFlag = 0;\n frontalState.totalNodes = numNodes;\n frontalState.transformationFlag = 0;\n frontalState.nodesPerElement = Array(numElements).fill(0);\n frontalState.determinant = 1;\n\n // For matrix operations, estimate required size based on problem complexity\n const systemSize = Math.max(numNodes, 2000);\n frontalState.globalSolutionVector = Array(systemSize).fill(0);\n frontalState.frontDataIndex = 0;\n\n // Initialize elementData arrays\n elementData.localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n elementData.currentElementIndex = 0;\n\n // Initialize frontStorage arrays\n const frontSize = estimateFrontSize(numNodes, numElements);\n frontStorage.frontValues = Array(frontSize).fill(0);\n frontStorage.columnHeaders = Array(systemSize).fill(0);\n frontStorage.pivotRow = Array(systemSize).fill(0);\n frontStorage.pivotData = Array(frontSize).fill(0);\n}\n\n/**\n * Function to estimate the required front size\n * @param {number} numNodes - Number of of nodes per element\n * @param {number} numElements - Number of elements in the mesh\n * @returns {number} Estimated front size\n */\nfunction estimateFrontSize(numNodes, numElements) {\n const frontWidthEstimate = Math.max(Math.ceil(Math.sqrt(numElements)) * numNodes, numNodes * 2);\n return frontWidthEstimate * numElements;\n}\n// Old function to estimate the required front size\n// function estimateFrontSize(numNodes, numElements, numNodes) {\n// const frontWidthEstimate = Math.ceil(Math.sqrt(numElements) * numNodes * 2);\n// const frontSize = frontWidthEstimate * numNodes * 4;\n// return Math.max(frontSize, 10000);\n// }\n\n/**\n * Function to compute local Jacobian matrix and local residual vector\n * @param {object} meshData - Object containing mesh data\n * @param {object} FEAData - Object containing FEA-related data\n * @param {object} thermalBoundaryConditions - Object containing thermal boundary conditions\n * @param {function} assembleFront - Matrix assembler based on the physical model\n */\nfunction assembleElementContribution(meshData, FEAData, thermalBoundaryConditions, assembleFront) {\n const elementIndex = elementData.currentElementIndex - 1;\n\n // Guard against out-of-range indices\n if (elementIndex < 0 || elementIndex >= meshData.totalElements) {\n errorLog(`Skipping out-of-range elementIndex=${elementIndex} (totalElements=${meshData.totalElements})`);\n return false;\n }\n\n // Domain terms\n const { localJacobianMatrix, localResidualVector, ngl } = assembleFront({\n elementIndex,\n nop: frontalData.nodalNumbering,\n meshData,\n basisFunctions: basisFunctions,\n FEAData,\n // These are ignored by linear assemblers\n solutionVector: frontalState.currentSolutionVector,\n eikonalActivationFlag: frontalState.eikonalActivationFlag,\n });\n\n // Handle Robin-type boundary conditions differently based on which solver is being used\n let boundaryLocalJacobianMatrix = Array(FEAData.numNodes)\n .fill()\n .map(() => Array(FEAData.numNodes).fill(0));\n let boundaryResidualVector = Array(FEAData.numNodes).fill(0);\n\n // heatConductionScript solver\n if (assembleFront === assembleHeatConductionFront) {\n // Check if this element is on a Robin-type boundary\n let isOnRobinTypeBoundary = false;\n for (const boundaryKey in meshData.boundaryElements) {\n if (\n thermalBoundaryConditions.boundaryConditions[boundaryKey]?.[0] === \"convection\" &&\n meshData.boundaryElements[boundaryKey].some(([elemIdx, _]) => elemIdx === elementIndex)\n ) {\n isOnRobinTypeBoundary = true;\n break;\n }\n }\n\n // Only calculate Robin-type for elements when required\n if (isOnRobinTypeBoundary) {\n const { gaussPoints, gaussWeights } = FEAData;\n const result = thermalBoundaryConditions.imposeConvectionBoundaryConditionsFront(\n elementIndex,\n meshData.nodesXCoordinates,\n meshData.nodesYCoordinates,\n gaussPoints,\n gaussWeights,\n basisFunctions\n );\n boundaryLocalJacobianMatrix = result.localJacobianMatrix;\n boundaryResidualVector = result.localResidualVector;\n }\n } else if (assembleFront === assembleFrontPropagationFront) {\n // For now, no Robin-type boundary conditions exist for any other solver\n }\n\n // Combine domain and boundary contributions\n for (let localNodeI = 0; localNodeI < FEAData.numNodes; localNodeI++) {\n for (let localNodeJ = 0; localNodeJ < FEAData.numNodes; localNodeJ++) {\n elementData.localJacobianMatrix[localNodeI][localNodeJ] =\n localJacobianMatrix[localNodeI][localNodeJ] + boundaryLocalJacobianMatrix[localNodeI][localNodeJ];\n }\n }\n\n // Assemble local element residual\n for (let localNodeIndex = 0; localNodeIndex < FEAData.numNodes; localNodeIndex++) {\n const globalNodeIndex = ngl[localNodeIndex] - 1;\n frontalData.globalResidualVector[globalNodeIndex] +=\n localResidualVector[localNodeIndex] + boundaryResidualVector[localNodeIndex];\n }\n\n return true;\n}\n\n/**\n * Function to implement the frontal solver algorithm\n * @param {object} meshData - Object containing mesh data\n * @param {object} FEAData - Object containing FEA-related data\n * @param {object} thermalBoundaryConditions - Object containing thermal boundary conditions\n * @param {function} assembleFront - Matrix assembler based on the physical model\n */\nfunction runFrontalAlgorithm(meshData, FEAData, thermalBoundaryConditions, assembleFront) {\n // Allocate local arrays dynamically\n const totalElements = meshData.totalElements;\n const numNodes = meshData.nodesXCoordinates.length;\n const systemSize = Math.max(numNodes, frontalState.globalSolutionVector.length);\n let localDestination = Array(FEAData.numNodes).fill(0);\n let rowDestination = Array(FEAData.numNodes).fill(0);\n let rowHeaders = Array(systemSize).fill(0);\n let pivotRowIndices = Array(systemSize).fill(0);\n let pivotColumnIndices = Array(systemSize).fill(0);\n let modifiedRows = Array(systemSize).fill(0);\n let pivotColumn = Array(systemSize).fill(0);\n let frontMatrix = Array(systemSize)\n .fill()\n .map(() => Array(systemSize).fill(0));\n let rowSwapCount = Array(numNodes).fill(0);\n let columnSwapCount = Array(numNodes).fill(0);\n let lastAppearanceCheck = Array(numNodes).fill(0);\n let pivotColumnGlobalIndex; // Pivot column global index\n\n let frontDataCounter = 1;\n frontalState.writeFlag++;\n let pivotDataIndex = 1;\n let summedRows = 1;\n elementData.currentElementIndex = 0;\n\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n rowSwapCount[nodeIndex] = 0;\n columnSwapCount[nodeIndex] = 0;\n }\n\n if (frontalState.transformationFlag !== 0) {\n // Prefront: find last appearance of each node\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n lastAppearanceCheck[nodeIndex] = 0;\n }\n\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n let reverseElementIndex = totalElements - elementIndex - 1;\n for (\n let localNodeIndex = 0;\n localNodeIndex < frontalState.nodesPerElement[reverseElementIndex];\n localNodeIndex++\n ) {\n let globalNodeIndex = frontalData.nodalNumbering[reverseElementIndex][localNodeIndex];\n if (lastAppearanceCheck[globalNodeIndex - 1] === 0) {\n lastAppearanceCheck[globalNodeIndex - 1] = 1;\n frontalData.nodalNumbering[reverseElementIndex][localNodeIndex] =\n -frontalData.nodalNumbering[reverseElementIndex][localNodeIndex];\n }\n }\n }\n }\n\n frontalState.transformationFlag = 0;\n let columnCount = 0;\n let rowCount = 0;\n\n for (let i = 0; i < systemSize; i++) {\n for (let j = 0; j < systemSize; j++) {\n frontMatrix[j][i] = 0;\n }\n }\n\n while (true) {\n // Assemble a new element only while we still have elements\n let assembled = false;\n let numElementNodes = 0;\n let numElementColumns = 0;\n\n if (elementData.currentElementIndex < totalElements) {\n elementData.currentElementIndex++;\n assembled = assembleElementContribution(meshData, FEAData, thermalBoundaryConditions, assembleFront);\n }\n\n if (assembled) {\n const currentElement = elementData.currentElementIndex;\n numElementNodes = frontalState.nodesPerElement[currentElement - 1];\n numElementColumns = frontalState.nodesPerElement[currentElement - 1];\n\n for (let localNodeIndex = 0; localNodeIndex < numElementColumns; localNodeIndex++) {\n let globalNodeIndex = frontalData.nodalNumbering[currentElement - 1][localNodeIndex];\n let columnIndex;\n\n if (columnCount === 0) {\n columnCount++;\n localDestination[localNodeIndex] = columnCount;\n frontStorage.columnHeaders[columnCount - 1] = globalNodeIndex;\n } else {\n for (columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n if (Math.abs(globalNodeIndex) === Math.abs(frontStorage.columnHeaders[columnIndex])) break;\n }\n\n if (columnIndex === columnCount) {\n columnCount++;\n localDestination[localNodeIndex] = columnCount;\n frontStorage.columnHeaders[columnCount - 1] = globalNodeIndex;\n } else {\n localDestination[localNodeIndex] = columnIndex + 1;\n frontStorage.columnHeaders[columnIndex] = globalNodeIndex;\n }\n }\n\n let rowIndex;\n if (rowCount === 0) {\n rowCount++;\n rowDestination[localNodeIndex] = rowCount;\n rowHeaders[rowCount - 1] = globalNodeIndex;\n } else {\n for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n if (Math.abs(globalNodeIndex) === Math.abs(rowHeaders[rowIndex])) break;\n }\n\n if (rowIndex === rowCount) {\n rowCount++;\n rowDestination[localNodeIndex] = rowCount;\n rowHeaders[rowCount - 1] = globalNodeIndex;\n } else {\n rowDestination[localNodeIndex] = rowIndex + 1;\n rowHeaders[rowIndex] = globalNodeIndex;\n }\n }\n }\n\n if (rowCount > systemSize || columnCount > systemSize) {\n errorLog(\"Error: systemSize not large enough\");\n return;\n }\n\n for (let localColumnIndex = 0; localColumnIndex < numElementColumns; localColumnIndex++) {\n let frontColumnIndex = localDestination[localColumnIndex];\n for (let localRowIndex = 0; localRowIndex < numElementNodes; localRowIndex++) {\n let frontRowIndex = rowDestination[localRowIndex];\n frontMatrix[frontRowIndex - 1][frontColumnIndex - 1] +=\n elementData.localJacobianMatrix[localRowIndex][localColumnIndex];\n }\n }\n }\n\n // Pivoting/elimination continues whether or not a new element was assembled\n let availableColumnCount = 0;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n if (frontStorage.columnHeaders[columnIndex] < 0) {\n pivotColumnIndices[availableColumnCount] = columnIndex + 1;\n availableColumnCount++;\n }\n }\n\n let constrainedRowCount = 0;\n let availableRowCount = 0;\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n let globalNodeIndex = rowHeaders[rowIndex];\n if (globalNodeIndex < 0) {\n pivotRowIndices[availableRowCount] = rowIndex + 1;\n availableRowCount++;\n let absoluteNodeIndex = Math.abs(globalNodeIndex);\n if (frontalData.nodeConstraintCode[absoluteNodeIndex - 1] === 1) {\n modifiedRows[constrainedRowCount] = rowIndex + 1;\n constrainedRowCount++;\n frontalData.nodeConstraintCode[absoluteNodeIndex - 1] = 2;\n frontalData.globalResidualVector[absoluteNodeIndex - 1] =\n frontalData.boundaryValues[absoluteNodeIndex - 1];\n }\n }\n }\n\n if (constrainedRowCount > 0) {\n for (let constrainedIndex = 0; constrainedIndex < constrainedRowCount; constrainedIndex++) {\n let rowIndex = modifiedRows[constrainedIndex] - 1;\n let globalNodeIndex = Math.abs(rowHeaders[rowIndex]);\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex][columnIndex] = 0;\n let columnGlobalIndex = Math.abs(frontStorage.columnHeaders[columnIndex]);\n if (columnGlobalIndex === globalNodeIndex) frontMatrix[rowIndex][columnIndex] = 1;\n }\n }\n }\n\n if (availableColumnCount > summedRows || elementData.currentElementIndex < totalElements) {\n if (availableColumnCount === 0) {\n errorLog(\"Error: no more rows fully summed\");\n return;\n }\n\n let pivotRowIndex = pivotRowIndices[0];\n let pivotColumnIndex = pivotColumnIndices[0];\n let pivotValue = frontMatrix[pivotRowIndex - 1][pivotColumnIndex - 1];\n\n if (Math.abs(pivotValue) < 1e-4) {\n pivotValue = 0;\n for (let columnIndex = 0; columnIndex < availableColumnCount; columnIndex++) {\n let testColumnIndex = pivotColumnIndices[columnIndex];\n for (let rowIndex = 0; rowIndex < availableRowCount; rowIndex++) {\n let testRowIndex = pivotRowIndices[rowIndex];\n let testValue = frontMatrix[testRowIndex - 1][testColumnIndex - 1];\n if (Math.abs(testValue) > Math.abs(pivotValue)) {\n pivotValue = testValue;\n pivotColumnIndex = testColumnIndex;\n pivotRowIndex = testRowIndex;\n }\n }\n }\n }\n\n let pivotGlobalRowIndex = Math.abs(rowHeaders[pivotRowIndex - 1]);\n pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[pivotColumnIndex - 1]); // Assign, don't declare\n let permutationHelper =\n pivotGlobalRowIndex +\n pivotColumnGlobalIndex +\n rowSwapCount[pivotGlobalRowIndex - 1] +\n columnSwapCount[pivotColumnGlobalIndex - 1];\n frontalState.determinant =\n (frontalState.determinant * pivotValue * (-1) ** permutationHelper) / Math.abs(pivotValue);\n\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n if (nodeIndex >= pivotGlobalRowIndex) rowSwapCount[nodeIndex]--;\n if (nodeIndex >= pivotColumnGlobalIndex) columnSwapCount[nodeIndex]--;\n }\n\n if (Math.abs(pivotValue) < 1e-10) {\n errorLog(\n `Matrix singular or ill-conditioned, currentElementIndex=${elementData.currentElementIndex}, pivotGlobalRowIndex=${pivotGlobalRowIndex}, pivotColumnGlobalIndex=${pivotColumnGlobalIndex}, pivotValue=${pivotValue}`\n );\n }\n\n if (pivotValue === 0) return;\n\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.pivotRow[columnIndex] = frontMatrix[pivotRowIndex - 1][columnIndex] / pivotValue;\n }\n\n let rightHandSide = frontalData.globalResidualVector[pivotGlobalRowIndex - 1] / pivotValue;\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] = rightHandSide;\n pivotColumn[pivotRowIndex - 1] = pivotValue;\n\n if (pivotRowIndex > 1) {\n for (let rowIndex = 0; rowIndex < pivotRowIndex - 1; rowIndex++) {\n let globalRowIndex = Math.abs(rowHeaders[rowIndex]);\n let eliminationFactor = frontMatrix[rowIndex][pivotColumnIndex - 1];\n pivotColumn[rowIndex] = eliminationFactor;\n if (pivotColumnIndex > 1 && eliminationFactor !== 0) {\n for (let columnIndex = 0; columnIndex < pivotColumnIndex - 1; columnIndex++) {\n frontMatrix[rowIndex][columnIndex] -= eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n if (pivotColumnIndex < columnCount) {\n for (let columnIndex = pivotColumnIndex; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex][columnIndex - 1] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n frontalData.globalResidualVector[globalRowIndex - 1] -= eliminationFactor * rightHandSide;\n }\n }\n\n if (pivotRowIndex < rowCount) {\n for (let rowIndex = pivotRowIndex; rowIndex < rowCount; rowIndex++) {\n let globalRowIndex = Math.abs(rowHeaders[rowIndex]);\n let eliminationFactor = frontMatrix[rowIndex][pivotColumnIndex - 1];\n pivotColumn[rowIndex] = eliminationFactor;\n if (pivotColumnIndex > 1) {\n for (let columnIndex = 0; columnIndex < pivotColumnIndex - 1; columnIndex++) {\n frontMatrix[rowIndex - 1][columnIndex] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n if (pivotColumnIndex < columnCount) {\n for (let columnIndex = pivotColumnIndex; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex - 1][columnIndex - 1] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n frontalData.globalResidualVector[globalRowIndex - 1] -= eliminationFactor * rightHandSide;\n }\n }\n\n for (let i = 0; i < rowCount; i++) {\n frontStorage.pivotData[pivotDataIndex + i - 1] = pivotColumn[i];\n }\n pivotDataIndex += rowCount;\n\n for (let i = 0; i < rowCount; i++) {\n frontStorage.pivotData[pivotDataIndex + i - 1] = rowHeaders[i];\n }\n pivotDataIndex += rowCount;\n\n frontStorage.pivotData[pivotDataIndex - 1] = pivotRowIndex;\n pivotDataIndex++;\n\n for (let i = 0; i < columnCount; i++) {\n frontStorage.frontValues[frontDataCounter - 1 + i] = frontStorage.pivotRow[i];\n }\n frontDataCounter += columnCount;\n\n for (let i = 0; i < columnCount; i++) {\n frontStorage.frontValues[frontDataCounter - 1 + i] = frontStorage.columnHeaders[i];\n }\n frontDataCounter += columnCount;\n\n frontStorage.frontValues[frontDataCounter - 1] = pivotGlobalRowIndex;\n frontStorage.frontValues[frontDataCounter] = columnCount;\n frontStorage.frontValues[frontDataCounter + 1] = pivotColumnIndex;\n frontStorage.frontValues[frontDataCounter + 2] = pivotValue;\n frontDataCounter += 4;\n\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n frontMatrix[rowIndex][columnCount - 1] = 0;\n }\n\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowCount - 1][columnIndex] = 0;\n }\n\n columnCount--;\n if (pivotColumnIndex < columnCount + 1) {\n for (let columnIndex = pivotColumnIndex - 1; columnIndex < columnCount; columnIndex++) {\n frontStorage.columnHeaders[columnIndex] = frontStorage.columnHeaders[columnIndex + 1];\n }\n }\n\n rowCount--;\n if (pivotRowIndex < rowCount + 1) {\n for (let rowIndex = pivotRowIndex - 1; rowIndex < rowCount; rowIndex++) {\n rowHeaders[rowIndex] = rowHeaders[rowIndex + 1];\n }\n }\n\n if (rowCount > 1 || elementData.currentElementIndex < totalElements) continue;\n\n pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[0]); // Assign, don't declare\n pivotRowIndex = 1;\n pivotValue = frontMatrix[0][0];\n pivotGlobalRowIndex = Math.abs(rowHeaders[0]);\n pivotColumnIndex = 1;\n permutationHelper =\n pivotGlobalRowIndex +\n pivotColumnGlobalIndex +\n rowSwapCount[pivotGlobalRowIndex - 1] +\n columnSwapCount[pivotColumnGlobalIndex - 1];\n frontalState.determinant =\n (frontalState.determinant * pivotValue * (-1) ** permutationHelper) / Math.abs(pivotValue);\n\n frontStorage.pivotRow[0] = 1;\n if (Math.abs(pivotValue) < 1e-10) {\n errorLog(\n `Matrix singular or ill-conditioned, currentElementIndex=${elementData.currentElementIndex}, pivotGlobalRowIndex=${pivotGlobalRowIndex}, pivotColumnGlobalIndex=${pivotColumnGlobalIndex}, pivotValue=${pivotValue}`\n );\n }\n\n if (pivotValue === 0) return;\n\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] =\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] / pivotValue;\n frontStorage.frontValues[frontDataCounter - 1] = frontStorage.pivotRow[0];\n frontDataCounter++;\n frontStorage.frontValues[frontDataCounter - 1] = frontStorage.columnHeaders[0];\n frontDataCounter++;\n frontStorage.frontValues[frontDataCounter - 1] = pivotGlobalRowIndex;\n frontStorage.frontValues[frontDataCounter] = columnCount;\n frontStorage.frontValues[frontDataCounter + 1] = pivotColumnIndex;\n frontStorage.frontValues[frontDataCounter + 2] = pivotValue;\n frontDataCounter += 4;\n\n frontStorage.pivotData[pivotDataIndex - 1] = pivotColumn[0];\n pivotDataIndex++;\n frontStorage.pivotData[pivotDataIndex - 1] = rowHeaders[0];\n pivotDataIndex++;\n frontStorage.pivotData[pivotDataIndex - 1] = pivotRowIndex;\n pivotDataIndex++;\n\n frontalState.frontDataIndex = frontDataCounter;\n if (frontalState.writeFlag === 1)\n debugLog(`total ecs transfer in matrix reduction=${frontDataCounter}`);\n\n // Back substitution\n performBackSubstitution(frontDataCounter);\n break;\n }\n }\n}\n\n/**\n * Function to perform back substitution for the frontal solver\n * @param {number} frontDataCounter - Index counter for the element contributions\n */\nfunction performBackSubstitution(frontDataCounter) {\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n frontalState.globalSolutionVector[nodeIndex] = frontalData.boundaryValues[nodeIndex];\n }\n\n for (let iterationIndex = 1; iterationIndex <= frontalState.totalNodes; iterationIndex++) {\n frontDataCounter -= 4;\n let pivotGlobalRowIndex = frontStorage.frontValues[frontDataCounter - 1];\n let columnCount = frontStorage.frontValues[frontDataCounter];\n let pivotColumnIndex = frontStorage.frontValues[frontDataCounter + 1];\n let pivotValue = frontStorage.frontValues[frontDataCounter + 2];\n\n if (iterationIndex === 1) {\n frontDataCounter--;\n frontStorage.columnHeaders[0] = frontStorage.frontValues[frontDataCounter - 1];\n frontDataCounter--;\n frontStorage.pivotRow[0] = frontStorage.frontValues[frontDataCounter - 1];\n } else {\n frontDataCounter -= columnCount;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.columnHeaders[columnIndex] =\n frontStorage.frontValues[frontDataCounter - 1 + columnIndex];\n }\n frontDataCounter -= columnCount;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.pivotRow[columnIndex] = frontStorage.frontValues[frontDataCounter - 1 + columnIndex];\n }\n }\n\n let pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[pivotColumnIndex - 1]);\n if (frontalData.nodeConstraintCode[pivotColumnGlobalIndex - 1] > 0) continue;\n\n let accumulatedValue = 0;\n frontStorage.pivotRow[pivotColumnIndex - 1] = 0;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n accumulatedValue -=\n frontStorage.pivotRow[columnIndex] *\n frontalState.globalSolutionVector[Math.abs(frontStorage.columnHeaders[columnIndex]) - 1];\n }\n\n frontalState.globalSolutionVector[pivotColumnGlobalIndex - 1] =\n accumulatedValue + frontalData.globalResidualVector[pivotGlobalRowIndex - 1];\n\n frontalData.nodeConstraintCode[pivotColumnGlobalIndex - 1] = 1;\n }\n\n if (frontalState.writeFlag === 1)\n debugLog(`value of frontDataCounter after backsubstitution=${frontDataCounter}`);\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 { runFrontalSolver } from \"./frontalSolverScript.js\";\nimport { assembleFrontPropagationFront } from \"../solvers/frontPropagationScript.js\";\n\n/**\n * Function to solve a system of non-linear equations using the Newton-Raphson method\n * @param {function} assembleMat - Matrix assembler based on the physical model\n * @param {object} context - Context object containing simulation data and options\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\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 // Check if using frontal solver\n if (context.solverMethod === \"frontal\") {\n const frontalResult = runFrontalSolver(\n assembleFrontPropagationFront,\n context.meshData,\n context.boundaryConditions,\n { solutionVector, eikonalActivationFlag: context.eikonalActivationFlag }\n );\n deltaX = frontalResult.solutionVector;\n } else {\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\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 * @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 { assembleGeneralFormPDEMat, assembleGeneralFormPDEFront } from \"./solvers/generalFormPDEScript.js\";\nimport { assembleHeatConductionMat, assembleHeatConductionFront } from \"./solvers/heatConductionScript.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 this.coefficientFunctions = null; // Add storage for coefficient functions\n basicLog(\"FEAScriptModel instance created\");\n }\n\n /**\n * Sets the solver configuration\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} [options] - Optional additional configuration\n */\n setSolverConfig(solverConfig, options = {}) {\n this.solverConfig = solverConfig;\n\n // Store coefficient functions if provided\n if (options && options.coefficientFunctions) {\n this.coefficientFunctions = options.coefficientFunctions;\n debugLog(\"Coefficient functions set\");\n }\n\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 /**\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\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 === \"heatConductionScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Check if using frontal solver\n if (this.solverMethod === \"frontal\") {\n const frontalResult = runFrontalSolver(\n assembleHeatConductionFront,\n meshData,\n this.boundaryConditions\n );\n solutionVector = frontalResult.solutionVector;\n } else {\n // Use regular linear solver methods\n ({ jacobianMatrix, residualVector } = assembleHeatConductionMat(meshData, this.boundaryConditions));\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 } else if (this.solverConfig === \"generalFormPDEScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n // Check if using frontal solver\n if (this.solverMethod === \"frontal\") {\n errorLog(\n \"Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.\"\n );\n } else {\n // Use regular linear solver methods\n ({ jacobianMatrix, residualVector } = assembleGeneralFormPDEMat(\n meshData,\n this.boundaryConditions,\n this.coefficientFunctions\n ));\n\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\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 { initializeFEA, performIsoparametricMapping1D } from \"../mesh/meshUtilsScript.js\";\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the Jacobian matrix and residuals vector for the general form PDE model\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions\n * @param {object} coefficientFunctions - Functions A(x), B(x), C(x), D(x) for the PDE\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n */\nexport function assembleGeneralFormPDEMat(meshData, boundaryConditions, coefficientFunctions) {\n basicLog(\"Starting general form PDE 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 // Extract coefficient functions\n const { A, B, C, D } = coefficientFunctions;\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 if (meshDimension === \"1D\") {\n // 1D general form PDE\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 // Convert to 0-based indexing\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex = 0; gaussPointIndex < gaussPoints.length; gaussPointIndex++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < numNodes; i++) {\n xCoord += nodesXCoordinates[localToGlobalMap[i]] * basisFunction[i];\n }\n\n // Evaluate coefficient functions at this physical coordinate\n const a = A(xCoord);\n const b = B(xCoord);\n const c = C(xCoord);\n const d = D(xCoord);\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n const globalNodeIndex1 = localToGlobalMap[localNodeIndex1];\n\n // Source term contribution to residual vector\n residualVector[globalNodeIndex1] -=\n gaussWeights[gaussPointIndex] * detJacobian * d * basisFunction[localNodeIndex1];\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n const globalNodeIndex2 = localToGlobalMap[localNodeIndex2];\n\n // Diffusion term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n a *\n basisFunctionDerivX[localNodeIndex1] *\n basisFunctionDerivX[localNodeIndex2];\n\n // Advection term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n b *\n basisFunctionDerivX[localNodeIndex2] *\n basisFunction[localNodeIndex1];\n\n // Reaction term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n c *\n basisFunction[localNodeIndex1] *\n basisFunction[localNodeIndex2];\n }\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n errorLog(\"2D general form PDE is not yet supported in assembleGeneralFormPDEMat.\");\n // 2D general form PDE - empty for now\n }\n\n // Apply boundary conditions\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Apply Dirichlet boundary conditions only\n genericBoundaryConditions.imposeDirichletBoundaryConditions(residualVector, jacobianMatrix);\n\n basicLog(\"General form PDE matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n\n/**\n * Function to assemble the frontal solver matrix for the general form PDE model\n * @param {object} data - Object containing element data for the frontal solver\n * @returns {object} An object containing local Jacobian matrix and residual vector\n */\nexport function assembleGeneralFormPDEFront({\n elementIndex,\n nop,\n meshData,\n basisFunctions,\n FEAData,\n coefficientFunctions,\n}) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n const { A, B, C, D } = coefficientFunctions;\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n if (meshDimension === \"1D\") {\n // 1D general form PDE\n\n // Loop over Gauss points\n for (let gaussPointIndex = 0; gaussPointIndex < gaussPoints.length; gaussPointIndex++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < numNodes; i++) {\n xCoord += nodesXCoordinates[localToGlobalMap[i]] * basisFunction[i];\n }\n\n // Evaluate coefficient functions at this physical coordinate\n const a = A(xCoord);\n const b = B(xCoord);\n const c = C(xCoord);\n const d = D(xCoord);\n\n // Computation of local Jacobian matrix and residual vector\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n // Source term contribution to local residual vector\n localResidualVector[localNodeIndex1] -=\n gaussWeights[gaussPointIndex] * detJacobian * d * basisFunction[localNodeIndex1];\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n // Diffusion term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n a *\n basisFunctionDerivX[localNodeIndex1] *\n basisFunctionDerivX[localNodeIndex2];\n\n // Advection term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n b *\n basisFunctionDerivX[localNodeIndex2] *\n basisFunction[localNodeIndex1];\n\n // Reaction term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n c *\n basisFunction[localNodeIndex1] *\n basisFunction[localNodeIndex2];\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n errorLog(\"2D general form PDE is not yet supported in assembleGeneralFormPDEFront.\");\n // 2D general form PDE - empty for now\n }\n\n return {\n localJacobianMatrix,\n localResidualVector,\n ngl,\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\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// | ____| ____| /\\ / ____| (_) | | //\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 } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const printVersion = \"0.1.3\";"],"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","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","nodesXCoordinates","totalNodesX","deltaX","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","meshData","totalNodes","colIndex","basisFunctions","gaussPointsAndWeights","localToGlobalMap","numNodes","performIsoparametricMapping1D","params","xCoordinates","ksiDerivX","localNodeIndex","detJacobian","basisFunctionDerivX","performIsoparametricMapping2D","yCoordinates","etaDerivX","ksiDerivY","etaDerivY","basisFunctionDerivY","ThermalBoundaryConditions","boundaryConditions","imposeConstantTempBoundaryConditions","Object","keys","boundaryKey","tempValue","globalNodeIndex","imposeConstantTempBoundaryConditionsFront","nodeConstraintCode","boundaryValues","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","basisFunctionsAndDerivatives","tangentVectorLength","localNodeIndex2","globalNodeIndex2","gaussPointIndex","imposeConvectionBoundaryConditionsFront","localJacobianMatrix","map","localResidualVector","boundaryElement","find","_","assembleHeatConductionFront","FEAData","ngl","gaussPointIndex1","localNodeIndex1","gaussPointIndex2","globalIndex","GenericBoundaryConditions","imposeDirichletBoundaryConditions","value","imposeConstantValueBoundaryConditionsFront","assembleFrontPropagationMat","eikonalActivationFlag","eikonalViscousTerm","totalElements","mappingResult","solutionDerivX","solutionDerivY","localToGlobalMap1","localToGlobalMap2","assembleFrontPropagationFront","frontalData","frontalState","elementData","currentElementIndex","frontStorage","runFrontalSolver","assembleFront","numElements","globalResidualVector","topologyData","lateralData","writeFlag","transformationFlag","nodesPerElement","determinant","systemSize","globalSolutionVector","frontDataIndex","frontSize","frontWidthEstimate","ceil","estimateFrontSize","frontValues","columnHeaders","pivotRow","pivotData","initializeFrontalArrays","dirichletBoundaryConditionsHandler","currentSolutionVector","thermalBoundaryConditions","pivotColumnGlobalIndex","localDestination","rowDestination","rowHeaders","pivotRowIndices","pivotColumnIndices","modifiedRows","pivotColumn","frontMatrix","rowSwapCount","columnSwapCount","lastAppearanceCheck","frontDataCounter","pivotDataIndex","summedRows","reverseElementIndex","columnCount","rowCount","assembled","numElementNodes","numElementColumns","assembleElementContribution","currentElement","columnIndex","rowIndex","localColumnIndex","frontColumnIndex","localRowIndex","availableColumnCount","constrainedRowCount","availableRowCount","absoluteNodeIndex","constrainedIndex","pivotRowIndex","pivotColumnIndex","pivotValue","testColumnIndex","testRowIndex","testValue","pivotGlobalRowIndex","permutationHelper","rightHandSide","globalRowIndex","eliminationFactor","performBackSubstitution","runFrontalAlgorithm","toExponential","finalNodesX","finalNodesY","slice","nodesCoordinates","boundaryLocalJacobianMatrix","boundaryResidualVector","isOnRobinTypeBoundary","some","result","localNodeI","localNodeJ","iterationIndex","accumulatedValue","newtonRaphson","assembleMat","context","errorNorm","initialSolution","Number","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","meshConfig","coefficientFunctions","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","mesh","nodesCoordinatesAndNumbering","prepareMesh","assembleHeatConductionMat","eikonalExteralIterations","newtonRaphsonResult","A","B","C","D","xCoord","a","b","d","globalNodeIndex1","assembleGeneralFormPDEMat","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","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","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","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"],"mappings":"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"} \ No newline at end of file diff --git a/dist/feascript.esm.js b/dist/feascript.esm.js index 2a85bd7..7861b2a 100644 --- a/dist/feascript.esm.js +++ b/dist/feascript.esm.js @@ -1,4 +1,4 @@ -function e(e){let t=0;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{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]=1,t[r]=s}))}else if("quadratic"===this.elementOrder){({0:[0],2:[2]})[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]=1,t[r]=s}))}}))}})):"2D"===this.meshDimension&&Object.keys(this.boundaryConditions).forEach((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]=1,t[r]=s}))}else if("quadratic"===this.elementOrder){({0:[0,3,6],1:[0,1,2],2:[2,5,8],3:[6,7,8]})[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]=1,t[r]=s}))}}))}}))}imposeConvectionBoundaryConditions(e,t,n,s,i,r,a){let l=[],d=[];Object.keys(this.boundaryConditions).forEach((e=>{const t=this.boundaryConditions[e];"convection"===t[0]&&(l[e]=t[1],d[e]=t[2])})),"1D"===this.meshDimension?Object.keys(this.boundaryConditions).forEach((n=>{if("convection"===this.boundaryConditions[n][0]){const s=l[n],i=d[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((u=>{if("convection"===this.boundaryConditions[u][0]){const c=l[u],m=d[u];o(`Boundary ${u}: Applying convection with heat transfer coefficient h=${c} W/(m²·K) and external temperature T∞=${m} K`),this.boundaryElements[u].forEach((([l,d])=>{if("linear"===this.elementOrder){let u,h,f,p,b;0===d?(u=n[0],h=0,f=0,p=3,b=2):1===d?(u=0,h=n[0],f=0,p=2,b=1):2===d?(u=n[0],h=1,f=1,p=4,b=2):3===d&&(u=1,h=n[0],f=2,p=4,b=1);let y=a.getBasisFunctions(u,h),g=y.basisFunction,E=y.basisFunctionDerivKsi,v=y.basisFunctionDerivEta,M=0,C=0,D=0,$=0;const F=this.nop[l].length;for(let e=0;e{const t=this.boundaryConditions[e];"convection"===t[0]&&(a[e]=t[1],l[e]=t[2])}));const d=this.nop[e].length,u=Array(d).fill().map((()=>Array(d).fill(0))),c=Array(d).fill(0);for(const m in this.boundaryElements)if("convection"===this.boundaryConditions[m]?.[0]){const h=a[m],f=l[m];o(`Boundary ${m}: Applying convection with heat transfer coefficient h=${h} W/(m²·K) and external temperature T∞=${f} K`);const p=this.boundaryElements[m].find((([t,n])=>t===e));if(p){const a=p[1];if("1D"===this.meshDimension){let t;"linear"===this.elementOrder?t=0===a?0:1:"quadratic"===this.elementOrder&&(t=0===a?0:2),o(` - Applied convection boundary condition to node ${t+1} (element ${e+1}, local node ${t+1})`),c[t]+=-h*f,u[t][t]+=h}else if("2D"===this.meshDimension)if("linear"===this.elementOrder){let o,l,m,p,b;0===a?(o=s[0],l=0,m=0,p=3,b=2):1===a?(o=0,l=s[0],m=0,p=2,b=1):2===a?(o=s[0],l=1,m=1,p=4,b=2):3===a&&(o=1,l=s[0],m=2,p=4,b=1);const y=r.getBasisFunctions(o,l),g=y.basisFunction,E=y.basisFunctionDerivKsi,v=y.basisFunctionDerivEta;let M,C=0,D=0,$=0,F=0;for(let o=0;oArray(a).fill(0))),m=Array(a).fill(0),p=Array(a),b=Array(a);for(let n=0;ne-1)),{detJacobian:h,basisFunctionDerivX:b,basisFunctionDerivY:y}=f({basisFunction:n,basisFunctionDerivKsi:s,basisFunctionDerivEta:u,nodesXCoordinates:l,nodesYCoordinates:d,localToGlobalMap:m,numNodes:a});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],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("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]=1,t[r]=s}))}else if("quadratic"===this.elementOrder){({0:[0],2:[2]})[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]=1,t[r]=s}))}}))}})):"2D"===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,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]=1,t[r]=s}))}else if("quadratic"===this.elementOrder){({0:[0,3,6],1:[0,1,2],2:[2,5,8],3:[6,7,8]})[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]=1,t[r]=s}))}}))}}))}}function g(e,t,n,i){s("Starting front propagation matrix assembly...");let r=1-i+.01;o(`eikonalViscousTerm: ${r}`),o(`eikonalActivationFlag: ${i}`);const{nodesXCoordinates:a,nodesYCoordinates:l,nop:d,boundaryElements:u,totalElements:c,meshDimension:p,elementOrder:b}=e,g=m(e),{residualVector:E,jacobianMatrix:v,localToGlobalMap:M,basisFunctions:C,gaussPoints:D,gaussWeights:$,numNodes:F}=g;for(let e=0;eArray(d).fill(0))),y=Array(d).fill(0),g=Array(d),E=Array(d);for(let n=0;nArray(e).fill(0))),v.nodeConstraintCode=Array(e).fill(0),v.boundaryValues=Array(e).fill(0),v.globalResidualVector=Array(e).fill(0),v.solutionVector=Array(e).fill(0),v.topologyData=Array(t).fill(0),v.lateralData=Array(t).fill(0),M.writeFlag=0,M.totalNodes=e,M.transformationFlag=0,M.nodesPerElement=Array(t).fill(0),M.determinant=1;const n=Math.max(e,2e3);M.globalSolutionVector=Array(n).fill(0),M.frontDataIndex=0,C.localJacobianMatrix=Array(e).fill().map((()=>Array(e).fill(0))),C.currentElementIndex=0;const o=function(e,t){const n=Math.max(Math.ceil(Math.sqrt(t))*e,2*e);return n*t}(e,t);D.frontValues=Array(o).fill(0),D.columnHeaders=Array(n).fill(0),D.pivotRow=Array(n).fill(0),D.pivotData=Array(o).fill(0)}(l.numNodes,u),s("Solving system using frontal..."),console.time("systemSolving"),$=new a({meshDimension:t.meshDimension,elementOrder:t.elementOrder});for(let e=0;eArray(l).fill(0))),g=Array(a).fill(0),E=Array(a).fill(0),$=Array(a).fill(0),F=1;M.writeFlag++;let N=1,w=1;C.currentElementIndex=0;for(let e=0;el||O>l)return void i("Error: systemSize not large enough");for(let e=0;e0)for(let e=0;ew||C.currentElementIndexMath.abs(n)&&(n=r,t=s,e=i)}}}let s=Math.abs(m[e-1]);d=Math.abs(D.columnHeaders[t-1]);let a=s+d+g[s-1]+E[d-1];M.determinant=M.determinant*n*(-1)**a/Math.abs(n);for(let e=0;e=s&&g[e]--,e>=d&&E[e]--;if(Math.abs(n)<1e-10&&i(`Matrix singular or ill-conditioned, currentElementIndex=${C.currentElementIndex}, pivotGlobalRowIndex=${s}, pivotColumnGlobalIndex=${d}, pivotValue=${n}`),0===n)return;for(let t=0;t1)for(let n=0;n1&&0!==o)for(let e=0;e1)for(let e=0;e1||C.currentElementIndex=e.totalElements)return i(`Skipping out-of-range elementIndex=${s} (totalElements=${e.totalElements})`),!1;const{localJacobianMatrix:r,localResidualVector:a,ngl:l}=o({elementIndex:s,nop:v.nodalNumbering,meshData:e,basisFunctions:$,FEAData:t,solutionVector:M.currentSolutionVector,eikonalActivationFlag:M.eikonalActivationFlag});let d=Array(t.numNodes).fill().map((()=>Array(t.numNodes).fill(0))),u=Array(t.numNodes).fill(0);if(o===b){let o=!1;for(const t in e.boundaryElements)if("convection"===n.boundaryConditions[t]?.[0]&&e.boundaryElements[t].some((([e,t])=>e===s))){o=!0;break}if(o){const{gaussPoints:o,gaussWeights:i}=t,r=n.imposeConvectionBoundaryConditionsFront(s,e.nodesXCoordinates,e.nodesYCoordinates,o,i,$);d=r.localJacobianMatrix,u=r.localResidualVector}}for(let e=0;e0)continue;let r=0;D.pivotRow[s-1]=0;for(let e=0;e100){i(`Solution not converged. Error norm: ${l}`);break}u++}return{solutionVector:m,converged:d,iterations:u,jacobianMatrix:h,residualVector:f}}class w{constructor(){this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",this.coefficientFunctions=null,s("FEAScriptModel instance created")}setSolverConfig(e,t={}){this.solverConfig=e,t&&t.coefficientFunctions&&(this.coefficientFunctions=t.coefficientFunctions,o("Coefficient functions set")),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=[],a=[];s("Preparing mesh...");const l=function(e){const{meshDimension:t,numElementsX:n,numElementsY:s,maxX:r,maxY:a,elementOrder:l,parsedMesh:c}=e;let m;"1D"===t?m=new d({numElementsX:n,maxX:r,elementOrder:l,parsedMesh:c}):"2D"===t?m=new u({numElementsX:n,maxX:r,numElementsY:s,maxY:a,elementOrder:l,parsedMesh:c}):i("Mesh dimension must be either '1D' or '2D'.");const h=m.boundaryElementsProcessed?m.parsedMesh:m.generateMesh();let f,p,b=h.nodesXCoordinates,y=h.nodesYCoordinates,g=h.totalNodesX,E=h.totalNodesY,v=h.nodalNumbering,M=h.boundaryElements;return null!=c?(f=v.length,p=b.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:b,nodesYCoordinates:y,totalNodesX:g,totalNodesY:E,nop:v,boundaryElements:M,totalElements:f,totalNodes:p,meshDimension:t,elementOrder:l}}(this.meshConfig);s("Mesh preparation completed");const c={nodesXCoordinates:l.nodesXCoordinates,nodesYCoordinates:l.nodesYCoordinates};if(s("Beginning solving process..."),console.time("totalSolvingTime"),"heatConductionScript"===this.solverConfig)if(s(`Using solver: ${this.solverConfig}`),"frontal"===this.solverMethod){n=F(b,l,this.boundaryConditions).solutionVector}else{({jacobianMatrix:e,residualVector:t}=function(e,t){s("Starting solid heat transfer matrix assembly...");const{nodesXCoordinates:n,nodesYCoordinates:o,nop:i,boundaryElements:r,totalElements:a,meshDimension:l,elementOrder:d}=e,u=m(e),{residualVector:c,jacobianMatrix:b,localToGlobalMap:y,basisFunctions:g,gaussPoints:E,gaussWeights:v,numNodes:M}=u;for(let e=0;e0&&(r.initialSolution=[...n]);const s=N(g,r,100,1e-4);e=s.jacobianMatrix,t=s.residualVector,n=s.solutionVector,o+=1/i}}else if("generalFormPDEScript"===this.solverConfig)if(s(`Using solver: ${this.solverConfig}`),"frontal"===this.solverMethod)i("Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.");else{({jacobianMatrix:e,residualVector:t}=function(e,t,n){s("Starting general form PDE matrix assembly...");const{nodesXCoordinates:o,nodesYCoordinates:r,nop:a,boundaryElements:l,totalElements:d,meshDimension:u,elementOrder:c}=e,{A:f,B:p,C:b,D:g}=n,E=m(e),{residualVector:v,jacobianMatrix:M,localToGlobalMap:C,basisFunctions:D,gaussPoints:$,gaussWeights:F,numNodes:A}=E;if("1D"===u)for(let e=0;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},u=0,c=[],m=0,h=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},b=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);b++,b===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};function X(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,u={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],u,{responsive:!0})}else if("2D"===o&&"contour"===s){const t="structured"===r,o=new Set(a).size,d=new Set(l).size;let u;u=Array.isArray(e[0])?e.map((e=>e[0])):e;let c=Math.min(window.innerWidth,700),m=Math.max(...a),h=Math.max(...l)/m,f=Math.min(c,600),p={title:`${s} plot - ${n}`,width:f,height:f*h*.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]),u=math.transpose(r),c=[];for(let e=0;e0&&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{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]=1,t[r]=s}))}else if("quadratic"===this.elementOrder){({0:[0],2:[2]})[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]=1,t[r]=s}))}}))}})):"2D"===this.meshDimension&&Object.keys(this.boundaryConditions).forEach((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]=1,t[r]=s}))}else if("quadratic"===this.elementOrder){({0:[0,3,6],1:[0,1,2],2:[2,5,8],3:[6,7,8]})[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]=1,t[r]=s}))}}))}}))}imposeConvectionBoundaryConditions(e,t,n,s,i,r,a){let l=[],d=[];Object.keys(this.boundaryConditions).forEach((e=>{const t=this.boundaryConditions[e];"convection"===t[0]&&(l[e]=t[1],d[e]=t[2])})),"1D"===this.meshDimension?Object.keys(this.boundaryConditions).forEach((n=>{if("convection"===this.boundaryConditions[n][0]){const s=l[n],i=d[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((u=>{if("convection"===this.boundaryConditions[u][0]){const c=l[u],m=d[u];o(`Boundary ${u}: Applying convection with heat transfer coefficient h=${c} W/(m²·K) and external temperature T∞=${m} K`),this.boundaryElements[u].forEach((([l,d])=>{if("linear"===this.elementOrder){let u,h,f,p,b;0===d?(u=n[0],h=0,f=0,p=3,b=2):1===d?(u=0,h=n[0],f=0,p=2,b=1):2===d?(u=n[0],h=1,f=1,p=4,b=2):3===d&&(u=1,h=n[0],f=2,p=4,b=1);let y=a.getBasisFunctions(u,h),g=y.basisFunction,E=y.basisFunctionDerivKsi,v=y.basisFunctionDerivEta,M=0,C=0,D=0,$=0;const F=this.nop[l].length;for(let e=0;e{const t=this.boundaryConditions[e];"convection"===t[0]&&(a[e]=t[1],l[e]=t[2])}));const d=this.nop[e].length,u=Array(d).fill().map((()=>Array(d).fill(0))),c=Array(d).fill(0);for(const m in this.boundaryElements)if("convection"===this.boundaryConditions[m]?.[0]){const h=a[m],f=l[m];o(`Boundary ${m}: Applying convection with heat transfer coefficient h=${h} W/(m²·K) and external temperature T∞=${f} K`);const p=this.boundaryElements[m].find((([t,n])=>t===e));if(p){const a=p[1];if("1D"===this.meshDimension){let t;"linear"===this.elementOrder?t=0===a?0:1:"quadratic"===this.elementOrder&&(t=0===a?0:2),o(` - Applied convection boundary condition to node ${t+1} (element ${e+1}, local node ${t+1})`),c[t]+=-h*f,u[t][t]+=h}else if("2D"===this.meshDimension)if("linear"===this.elementOrder){let o,l,m,p,b;0===a?(o=s[0],l=0,m=0,p=3,b=2):1===a?(o=0,l=s[0],m=0,p=2,b=1):2===a?(o=s[0],l=1,m=1,p=4,b=2):3===a&&(o=1,l=s[0],m=2,p=4,b=1);const y=r.getBasisFunctions(o,l),g=y.basisFunction,E=y.basisFunctionDerivKsi,v=y.basisFunctionDerivEta;let M,C=0,D=0,$=0,F=0;for(let o=0;oArray(a).fill(0))),m=Array(a).fill(0),p=Array(a),b=Array(a);for(let n=0;ne-1)),{detJacobian:h,basisFunctionDerivX:b,basisFunctionDerivY:y}=f({basisFunction:n,basisFunctionDerivKsi:s,basisFunctionDerivEta:u,nodesXCoordinates:l,nodesYCoordinates:d,localToGlobalMap:m,numNodes:a});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],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("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]=1,t[r]=s}))}else if("quadratic"===this.elementOrder){({0:[0],2:[2]})[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]=1,t[r]=s}))}}))}})):"2D"===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,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]=1,t[r]=s}))}else if("quadratic"===this.elementOrder){({0:[0,3,6],1:[0,1,2],2:[2,5,8],3:[6,7,8]})[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]=1,t[r]=s}))}}))}}))}}function g(e,t,n,i){s("Starting front propagation matrix assembly...");let r=1-i+.01;o(`eikonalViscousTerm: ${r}`),o(`eikonalActivationFlag: ${i}`);const{nodesXCoordinates:a,nodesYCoordinates:l,nop:d,boundaryElements:u,totalElements:c,meshDimension:p,elementOrder:b}=e,g=m(e),{residualVector:E,jacobianMatrix:v,localToGlobalMap:M,basisFunctions:C,gaussPoints:D,gaussWeights:$,numNodes:F}=g;for(let e=0;eArray(d).fill(0))),y=Array(d).fill(0),g=Array(d),E=Array(d);for(let n=0;nArray(e).fill(0))),v.nodeConstraintCode=Array(e).fill(0),v.boundaryValues=Array(e).fill(0),v.globalResidualVector=Array(e).fill(0),v.solutionVector=Array(e).fill(0),v.topologyData=Array(t).fill(0),v.lateralData=Array(t).fill(0),M.writeFlag=0,M.totalNodes=e,M.transformationFlag=0,M.nodesPerElement=Array(t).fill(0),M.determinant=1;const n=Math.max(e,2e3);M.globalSolutionVector=Array(n).fill(0),M.frontDataIndex=0,C.localJacobianMatrix=Array(e).fill().map((()=>Array(e).fill(0))),C.currentElementIndex=0;const o=function(e,t){const n=Math.max(Math.ceil(Math.sqrt(t))*e,2*e);return n*t}(e,t);D.frontValues=Array(o).fill(0),D.columnHeaders=Array(n).fill(0),D.pivotRow=Array(n).fill(0),D.pivotData=Array(o).fill(0)}(l.numNodes,u),s("Solving system using frontal..."),console.time("systemSolving"),$=new a({meshDimension:t.meshDimension,elementOrder:t.elementOrder});for(let e=0;eArray(l).fill(0))),g=Array(a).fill(0),E=Array(a).fill(0),$=Array(a).fill(0),F=1;M.writeFlag++;let N=1,w=1;C.currentElementIndex=0;for(let e=0;el||O>l)return void i("Error: systemSize not large enough");for(let e=0;e0)for(let e=0;ew||C.currentElementIndexMath.abs(n)&&(n=r,t=s,e=i)}}}let s=Math.abs(m[e-1]);d=Math.abs(D.columnHeaders[t-1]);let a=s+d+g[s-1]+E[d-1];M.determinant=M.determinant*n*(-1)**a/Math.abs(n);for(let e=0;e=s&&g[e]--,e>=d&&E[e]--;if(Math.abs(n)<1e-10&&i(`Matrix singular or ill-conditioned, currentElementIndex=${C.currentElementIndex}, pivotGlobalRowIndex=${s}, pivotColumnGlobalIndex=${d}, pivotValue=${n}`),0===n)return;for(let t=0;t1)for(let n=0;n1&&0!==o)for(let e=0;e1)for(let e=0;e1||C.currentElementIndex=e.totalElements)return i(`Skipping out-of-range elementIndex=${s} (totalElements=${e.totalElements})`),!1;const{localJacobianMatrix:r,localResidualVector:a,ngl:l}=o({elementIndex:s,nop:v.nodalNumbering,meshData:e,basisFunctions:$,FEAData:t,solutionVector:M.currentSolutionVector,eikonalActivationFlag:M.eikonalActivationFlag});let d=Array(t.numNodes).fill().map((()=>Array(t.numNodes).fill(0))),u=Array(t.numNodes).fill(0);if(o===b){let o=!1;for(const t in e.boundaryElements)if("convection"===n.boundaryConditions[t]?.[0]&&e.boundaryElements[t].some((([e,t])=>e===s))){o=!0;break}if(o){const{gaussPoints:o,gaussWeights:i}=t,r=n.imposeConvectionBoundaryConditionsFront(s,e.nodesXCoordinates,e.nodesYCoordinates,o,i,$);d=r.localJacobianMatrix,u=r.localResidualVector}}for(let e=0;e0)continue;let r=0;D.pivotRow[s-1]=0;for(let e=0;e100){i(`Solution not converged. Error norm: ${l}`);break}u++}return{solutionVector:m,converged:d,iterations:u,jacobianMatrix:h,residualVector:f}}class w{constructor(){this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",this.coefficientFunctions=null,s("FEAScriptModel instance created")}setSolverConfig(e,t={}){this.solverConfig=e,t&&t.coefficientFunctions&&(this.coefficientFunctions=t.coefficientFunctions,o("Coefficient functions set")),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=[],a=[];s("Preparing mesh...");const l=function(e){const{meshDimension:t,numElementsX:n,numElementsY:s,maxX:r,maxY:a,elementOrder:l,parsedMesh:c}=e;let m;"1D"===t?m=new d({numElementsX:n,maxX:r,elementOrder:l,parsedMesh:c}):"2D"===t?m=new u({numElementsX:n,maxX:r,numElementsY:s,maxY:a,elementOrder:l,parsedMesh:c}):i("Mesh dimension must be either '1D' or '2D'.");const h=m.boundaryElementsProcessed?m.parsedMesh:m.generateMesh();let f,p,b=h.nodesXCoordinates,y=h.nodesYCoordinates,g=h.totalNodesX,E=h.totalNodesY,v=h.nodalNumbering,M=h.boundaryElements;return null!=c?(f=v.length,p=b.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:b,nodesYCoordinates:y,totalNodesX:g,totalNodesY:E,nop:v,boundaryElements:M,totalElements:f,totalNodes:p,meshDimension:t,elementOrder:l}}(this.meshConfig);s("Mesh preparation completed");const c={nodesXCoordinates:l.nodesXCoordinates,nodesYCoordinates:l.nodesYCoordinates};if(s("Beginning solving process..."),console.time("totalSolvingTime"),"heatConductionScript"===this.solverConfig)if(s(`Using solver: ${this.solverConfig}`),"frontal"===this.solverMethod){n=F(b,l,this.boundaryConditions).solutionVector}else{({jacobianMatrix:e,residualVector:t}=function(e,t){s("Starting solid heat transfer matrix assembly...");const{nodesXCoordinates:n,nodesYCoordinates:o,nop:i,boundaryElements:r,totalElements:a,meshDimension:l,elementOrder:d}=e,u=m(e),{residualVector:c,jacobianMatrix:b,localToGlobalMap:y,basisFunctions:g,gaussPoints:E,gaussWeights:v,numNodes:M}=u;for(let e=0;e0&&(r.initialSolution=[...n]);const s=N(g,r,100,1e-4);e=s.jacobianMatrix,t=s.residualVector,n=s.solutionVector,o+=1/i}}else if("generalFormPDEScript"===this.solverConfig)if(s(`Using solver: ${this.solverConfig}`),"frontal"===this.solverMethod)i("Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.");else{({jacobianMatrix:e,residualVector:t}=function(e,t,n){s("Starting general form PDE matrix assembly...");const{nodesXCoordinates:o,nodesYCoordinates:r,nop:a,boundaryElements:l,totalElements:d,meshDimension:u,elementOrder:c}=e,{A:f,B:p,C:b,D:g}=n,E=m(e),{residualVector:v,jacobianMatrix:M,localToGlobalMap:C,basisFunctions:D,gaussPoints:$,gaussWeights:F,numNodes:A}=E;if("1D"===u)for(let e=0;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},u=0,c=[],m=0,h=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},b=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);b++,b===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};function X(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,u={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],u,{responsive:!0})}else if("2D"===o&&"contour"===s){const t="structured"===r,o=new Set(a).size,d=new Set(l).size;let u;u=Array.isArray(e[0])?e.map((e=>e[0])):e;let c=Math.min(window.innerWidth,700),m=Math.max(...a),h=Math.max(...l)/m,f=Math.min(c,600),p={title:`${s} plot - ${n}`,width:f,height:f*h*.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]),u=math.transpose(r),c=[];for(let e=0;e | |\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 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/**\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 * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\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 constant temperature boundary conditions for the frontal solver\n * @param {array} nodeConstraintCode - Array indicating boundary condition code for each node\n * @param {array} boundaryValues - Array containing boundary condition values\n */\n imposeConstantTempBoundaryConditionsFront(nodeConstraintCode, boundaryValues) {\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\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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 // 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 * Function to impose convection boundary conditions for the frontal solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @returns {object} An object containing:\n * - localJacobianMatrix: Local Jacobian matrix with convection contributions\n * - localResidualVector: Residual vector with convection contributions\n */\n imposeConvectionBoundaryConditionsFront(\n elementIndex,\n nodesXCoordinates,\n nodesYCoordinates,\n gaussPoints,\n gaussWeights,\n basisFunctions\n ) {\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 // Initialize local Jacobian matrix and local residual vector\n const numNodes = this.nop[elementIndex].length;\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Check if this element is on a convection boundary\n for (const boundaryKey in this.boundaryElements) {\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\n // Find if this element is on this boundary and which side\n const boundaryElement = this.boundaryElements[boundaryKey].find(\n ([elemIdx, _]) => elemIdx === elementIndex\n );\n\n if (boundaryElement) {\n const side = boundaryElement[1];\n\n if (this.meshDimension === \"1D\") {\n // Handle 1D case\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n nodeIndex = side === 0 ? 0 : 1;\n } else if (this.elementOrder === \"quadratic\") {\n nodeIndex = side === 0 ? 0 : 2;\n }\n\n // Add contribution to local Jacobian matrix and local residual vector\n debugLog(\n ` - Applied convection boundary condition to node ${nodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n localResidualVector[nodeIndex] += -convectionCoeff * extTemp;\n localJacobianMatrix[nodeIndex][nodeIndex] += convectionCoeff;\n } else if (this.meshDimension === \"2D\") {\n // Handle 2D case\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n\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 // Get basis functions\n const basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n const basisFunction = basisFunctionsAndDerivatives.basisFunction;\n const basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n const basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n // Calculate tangent vector components\n let ksiDerivX = 0,\n ksiDerivY = 0,\n etaDerivX = 0,\n etaDerivY = 0;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n } else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute tangent vector length\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 // Apply boundary conditions to local matrices\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n localResidualVector[localNodeIndex] +=\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 localJacobianMatrix[localNodeIndex][localNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n // Handle quadratic elements (similar pattern but with more Gauss points)\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n\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 // Apply boundary conditions to local matrices\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n localResidualVector[localNodeIndex] +=\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 localJacobianMatrix[localNodeIndex][localNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n }\n }\n }\n }\n\n return { localJacobianMatrix, localResidualVector };\n }\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 *\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\nexport function assembleHeatConductionMat(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 const 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 const 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 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\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\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 residual vector for the solid heat transfer model when using the frontal system solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nop - Nodal connectivity array (element-to-node mapping)\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @param {object} FEAData - Object containing FEA-related data\n * @returns {object} An object containing:\n * - localJacobianMatrix: Local Jacobian matrix\n * - localResidualVector: Residual vector contributions\n * - ngl: Array mapping local node indices to global node indices\n */\nexport function assembleHeatConductionFront({ elementIndex, nop, meshData, basisFunctions, FEAData }) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n // Loop over Gauss points\n if (meshDimension === \"1D\") {\n // 1D solid heat transfer\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n // 2D solid heat transfer\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } =\n basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1], gaussPoints[gaussPointIndex2]);\n\n // Create mapping from local element space to global mesh (convert to 0-based indexing)\n const localToGlobalMap = ngl.map((globalIndex) => globalIndex - 1);\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\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 return { localJacobianMatrix, localResidualVector, ngl };\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 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 Dirichlet boundary conditions\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n *\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\n imposeDirichletBoundaryConditions(residualVector, jacobianMatrix) {\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 value\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 value\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 value\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 value\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 * Function to impose constant value (Dirichlet) boundary conditions for the frontal solver\n * @param {array} nodeConstraintCode - Array indicating boundary condition code for each node\n * @param {array} boundaryValues - Array containing boundary condition values\n */\n imposeConstantValueBoundaryConditionsFront(nodeConstraintCode, boundaryValues) {\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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// Base viscous term that remains when eikonal equation is fully activated\nconst baseEikonalViscousTerm = 1e-2;\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 let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n debugLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n debugLog(`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 // Unsupported 1D front propagation\n errorLog(\"1D front propagation is not yet supported\");\n\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 // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // TODO 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 eikonalActivationFlag *\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 const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Dirichlet boundary conditions\n genericBoundaryConditions.imposeDirichletBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n\n/**\n * Function to assemble the local Jacobian matrix and residual vector for the front propagation model when using the frontal system solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nop - Nodal connectivity array (element-to-node mapping)\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @param {object} FEAData - Object containing FEA-related data\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 * - localJacobianMatrix: Local Jacobian matrix\n * - residualVector: Residual vector contributions\n * - ngl: Array mapping local node indices to global node indices\n */\nexport function assembleFrontPropagationFront({\n elementIndex,\n nop,\n meshData,\n basisFunctions,\n FEAData,\n solutionVector,\n eikonalActivationFlag,\n}) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n\n // Calculate eikonal viscous term\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(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 // Unsupported 1D front propagation\n errorLog(\"1D front propagation is not yet supported\");\n\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 // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // localJacobianMatrix\n // TODO localJacobianMatrix 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 // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } =\n basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1], gaussPoints[gaussPointIndex2]);\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\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 // Viscous term contribution\n localResidualVector[localNodeIndex1] +=\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 // Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n localResidualVector[localNodeIndex1] +=\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 // Viscous term contribution\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n\n // Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] +=\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 eikonalActivationFlag *\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 return { localJacobianMatrix, localResidualVector, ngl };\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 { initializeFEA } from \"../mesh/meshUtilsScript.js\";\nimport { assembleHeatConductionFront } from \"../solvers/heatConductionScript.js\";\nimport { ThermalBoundaryConditions } from \"../solvers/thermalBoundaryConditionsScript.js\";\nimport { assembleFrontPropagationFront } from \"../solvers/frontPropagationScript.js\";\nimport { GenericBoundaryConditions } from \"../solvers/genericBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// Create object templates\nconst frontalData = {};\nconst frontalState = {};\nconst elementData = { currentElementIndex: 0 };\nconst frontStorage = {};\nlet basisFunctions;\n\n/**\n * Function to run the frontal solver and obtain results for plotting\n * @param {function} assembleFront - Matrix assembler based on the physical model\n * @param {object} meshData - Object containing mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions\n * @param {object} [options] - Additional options for the solver\n * @returns {object} An object containing the solution vector and node coordinates\n */\nexport function runFrontalSolver(assembleFront, meshData, boundaryConditions, options = {}) {\n // Initialize FEA components\n const FEAData = initializeFEA(meshData);\n const totalNodes = meshData.nodesXCoordinates.length;\n const numElements = meshData.totalElements;\n const numNodes = FEAData.numNodes;\n\n // Calculate required array sizes\n initializeFrontalArrays(numNodes, numElements);\n\n // Start timing for system solving (frontal algorithm)\n basicLog(\"Solving system using frontal...\");\n console.time(\"systemSolving\");\n\n // Initialize basis functions\n basisFunctions = new BasisFunctions({\n meshDimension: meshData.meshDimension,\n elementOrder: meshData.elementOrder,\n });\n\n // Copy node connectivity array into frontalData storage\n for (let elementIndex = 0; elementIndex < meshData.totalElements; elementIndex++) {\n for (let nodeIndex = 0; nodeIndex < FEAData.numNodes; nodeIndex++) {\n frontalData.nodalNumbering[elementIndex][nodeIndex] = meshData.nop[elementIndex][nodeIndex];\n }\n }\n\n // Apply Dirichlet-type boundary conditions\n // Initialize all nodes with no boundary condition\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.nodeConstraintCode[nodeIndex] = 0;\n frontalData.boundaryValues[nodeIndex] = 0;\n }\n\n // Handle Dirichlet-type boundary conditions differently based on which solver is being used\n let dirichletBoundaryConditionsHandler;\n // Solid heat transfer model (heatConductionScript solver)\n if (assembleFront === assembleHeatConductionFront) {\n dirichletBoundaryConditionsHandler = new ThermalBoundaryConditions(\n boundaryConditions,\n meshData.boundaryElements,\n meshData.nop,\n meshData.meshDimension,\n meshData.elementOrder\n );\n\n dirichletBoundaryConditionsHandler.imposeConstantTempBoundaryConditionsFront(\n frontalData.nodeConstraintCode,\n frontalData.boundaryValues\n );\n // Front propagation model (frontPropagationScript solver)\n } else if (assembleFront === assembleFrontPropagationFront) {\n dirichletBoundaryConditionsHandler = new GenericBoundaryConditions(\n boundaryConditions,\n meshData.boundaryElements,\n meshData.nop,\n meshData.meshDimension,\n meshData.elementOrder\n );\n\n dirichletBoundaryConditionsHandler.imposeConstantValueBoundaryConditionsFront(\n frontalData.nodeConstraintCode,\n frontalData.boundaryValues\n );\n }\n // Initialize global residual vector\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.globalResidualVector[nodeIndex] = 0;\n }\n\n frontalState.totalNodes = meshData.nodesXCoordinates.length;\n frontalState.writeFlag = 0;\n frontalState.transformationFlag = 1;\n frontalState.determinant = 1;\n\n for (let elementIndex = 0; elementIndex < meshData.totalElements; elementIndex++) {\n frontalState.nodesPerElement[elementIndex] = FEAData.numNodes;\n }\n\n // Parameters for non-linear assemblers\n frontalState.currentSolutionVector = options.solutionVector;\n frontalState.eikonalActivationFlag = options.eikonalActivationFlag;\n\n // Pass assembleFront and dirichletBoundaryConditionsHandler to runFrontalAlgorithm\n runFrontalAlgorithm(meshData, FEAData, dirichletBoundaryConditionsHandler, assembleFront);\n\n // Copy solution\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.solutionVector[nodeIndex] = frontalState.globalSolutionVector[nodeIndex];\n }\n\n // Output results to console for debugging\n const { nodesXCoordinates, nodesYCoordinates } = meshData;\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n if (meshData.meshDimension === \"1D\") {\n // 1D case - only output X coordinates and temperature\n debugLog(\n `${nodesXCoordinates[nodeIndex].toExponential(5)} ${frontalData.solutionVector[\n nodeIndex\n ].toExponential(5)}`\n );\n } else {\n // 2D case - output X, Y coordinates and temperature\n debugLog(\n `${nodesXCoordinates[nodeIndex].toExponential(5)} ${nodesYCoordinates[nodeIndex].toExponential(\n 5\n )} ${frontalData.solutionVector[nodeIndex].toExponential(5)}`\n );\n }\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n const { nodesXCoordinates: finalNodesX, nodesYCoordinates: finalNodesY } = meshData;\n return {\n solutionVector: frontalData.solutionVector.slice(0, totalNodes),\n nodesCoordinates: {\n nodesXCoordinates: finalNodesX,\n nodesYCoordinates: finalNodesY,\n },\n };\n}\n\n/**\n * Function to initialize arrays dynamically based on problem size\n * @param {number} numNodes - Number of nodes per element\n * @param {number} numElements - Number of elements in the mesh\n */\nfunction initializeFrontalArrays(numNodes, numElements) {\n // Use the actual number of elements from the mesh\n frontalData.nodalNumbering = Array(numElements)\n .fill()\n .map(() => Array(numNodes).fill(0));\n frontalData.nodeConstraintCode = Array(numNodes).fill(0);\n frontalData.boundaryValues = Array(numNodes).fill(0);\n frontalData.globalResidualVector = Array(numNodes).fill(0);\n frontalData.solutionVector = Array(numNodes).fill(0);\n frontalData.topologyData = Array(numElements).fill(0);\n frontalData.lateralData = Array(numElements).fill(0);\n\n // Initialize frontalState arrays\n frontalState.writeFlag = 0;\n frontalState.totalNodes = numNodes;\n frontalState.transformationFlag = 0;\n frontalState.nodesPerElement = Array(numElements).fill(0);\n frontalState.determinant = 1;\n\n // For matrix operations, estimate required size based on problem complexity\n const systemSize = Math.max(numNodes, 2000);\n frontalState.globalSolutionVector = Array(systemSize).fill(0);\n frontalState.frontDataIndex = 0;\n\n // Initialize elementData arrays\n elementData.localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n elementData.currentElementIndex = 0;\n\n // Initialize frontStorage arrays\n const frontSize = estimateFrontSize(numNodes, numElements);\n frontStorage.frontValues = Array(frontSize).fill(0);\n frontStorage.columnHeaders = Array(systemSize).fill(0);\n frontStorage.pivotRow = Array(systemSize).fill(0);\n frontStorage.pivotData = Array(frontSize).fill(0);\n}\n\n/**\n * Function to estimate the required front size\n * @param {number} numNodes - Number of of nodes per element\n * @param {number} numElements - Number of elements in the mesh\n * @returns {number} Estimated front size\n */\nfunction estimateFrontSize(numNodes, numElements) {\n const frontWidthEstimate = Math.max(Math.ceil(Math.sqrt(numElements)) * numNodes, numNodes * 2);\n return frontWidthEstimate * numElements;\n}\n// Old function to estimate the required front size\n// function estimateFrontSize(numNodes, numElements, numNodes) {\n// const frontWidthEstimate = Math.ceil(Math.sqrt(numElements) * numNodes * 2);\n// const frontSize = frontWidthEstimate * numNodes * 4;\n// return Math.max(frontSize, 10000);\n// }\n\n/**\n * Function to compute local Jacobian matrix and local residual vector\n * @param {object} meshData - Object containing mesh data\n * @param {object} FEAData - Object containing FEA-related data\n * @param {object} thermalBoundaryConditions - Object containing thermal boundary conditions\n * @param {function} assembleFront - Matrix assembler based on the physical model\n */\nfunction assembleElementContribution(meshData, FEAData, thermalBoundaryConditions, assembleFront) {\n const elementIndex = elementData.currentElementIndex - 1;\n\n // Guard against out-of-range indices\n if (elementIndex < 0 || elementIndex >= meshData.totalElements) {\n errorLog(`Skipping out-of-range elementIndex=${elementIndex} (totalElements=${meshData.totalElements})`);\n return false;\n }\n\n // Domain terms\n const { localJacobianMatrix, localResidualVector, ngl } = assembleFront({\n elementIndex,\n nop: frontalData.nodalNumbering,\n meshData,\n basisFunctions: basisFunctions,\n FEAData,\n // These are ignored by linear assemblers\n solutionVector: frontalState.currentSolutionVector,\n eikonalActivationFlag: frontalState.eikonalActivationFlag,\n });\n\n // Handle Robin-type boundary conditions differently based on which solver is being used\n let boundaryLocalJacobianMatrix = Array(FEAData.numNodes)\n .fill()\n .map(() => Array(FEAData.numNodes).fill(0));\n let boundaryResidualVector = Array(FEAData.numNodes).fill(0);\n\n // heatConductionScript solver\n if (assembleFront === assembleHeatConductionFront) {\n // Check if this element is on a Robin-type boundary\n let isOnRobinTypeBoundary = false;\n for (const boundaryKey in meshData.boundaryElements) {\n if (\n thermalBoundaryConditions.boundaryConditions[boundaryKey]?.[0] === \"convection\" &&\n meshData.boundaryElements[boundaryKey].some(([elemIdx, _]) => elemIdx === elementIndex)\n ) {\n isOnRobinTypeBoundary = true;\n break;\n }\n }\n\n // Only calculate Robin-type for elements when required\n if (isOnRobinTypeBoundary) {\n const { gaussPoints, gaussWeights } = FEAData;\n const result = thermalBoundaryConditions.imposeConvectionBoundaryConditionsFront(\n elementIndex,\n meshData.nodesXCoordinates,\n meshData.nodesYCoordinates,\n gaussPoints,\n gaussWeights,\n basisFunctions\n );\n boundaryLocalJacobianMatrix = result.localJacobianMatrix;\n boundaryResidualVector = result.localResidualVector;\n }\n } else if (assembleFront === assembleFrontPropagationFront) {\n // For now, no Robin-type boundary conditions exist for any other solver\n }\n\n // Combine domain and boundary contributions\n for (let localNodeI = 0; localNodeI < FEAData.numNodes; localNodeI++) {\n for (let localNodeJ = 0; localNodeJ < FEAData.numNodes; localNodeJ++) {\n elementData.localJacobianMatrix[localNodeI][localNodeJ] =\n localJacobianMatrix[localNodeI][localNodeJ] + boundaryLocalJacobianMatrix[localNodeI][localNodeJ];\n }\n }\n\n // Assemble local element residual\n for (let localNodeIndex = 0; localNodeIndex < FEAData.numNodes; localNodeIndex++) {\n const globalNodeIndex = ngl[localNodeIndex] - 1;\n frontalData.globalResidualVector[globalNodeIndex] +=\n localResidualVector[localNodeIndex] + boundaryResidualVector[localNodeIndex];\n }\n\n return true;\n}\n\n/**\n * Function to implement the frontal solver algorithm\n * @param {object} meshData - Object containing mesh data\n * @param {object} FEAData - Object containing FEA-related data\n * @param {object} thermalBoundaryConditions - Object containing thermal boundary conditions\n * @param {function} assembleFront - Matrix assembler based on the physical model\n */\nfunction runFrontalAlgorithm(meshData, FEAData, thermalBoundaryConditions, assembleFront) {\n // Allocate local arrays dynamically\n const totalElements = meshData.totalElements;\n const numNodes = meshData.nodesXCoordinates.length;\n const systemSize = Math.max(numNodes, frontalState.globalSolutionVector.length);\n let localDestination = Array(FEAData.numNodes).fill(0);\n let rowDestination = Array(FEAData.numNodes).fill(0);\n let rowHeaders = Array(systemSize).fill(0);\n let pivotRowIndices = Array(systemSize).fill(0);\n let pivotColumnIndices = Array(systemSize).fill(0);\n let modifiedRows = Array(systemSize).fill(0);\n let pivotColumn = Array(systemSize).fill(0);\n let frontMatrix = Array(systemSize)\n .fill()\n .map(() => Array(systemSize).fill(0));\n let rowSwapCount = Array(numNodes).fill(0);\n let columnSwapCount = Array(numNodes).fill(0);\n let lastAppearanceCheck = Array(numNodes).fill(0);\n let pivotColumnGlobalIndex; // Pivot column global index\n\n let frontDataCounter = 1;\n frontalState.writeFlag++;\n let pivotDataIndex = 1;\n let summedRows = 1;\n elementData.currentElementIndex = 0;\n\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n rowSwapCount[nodeIndex] = 0;\n columnSwapCount[nodeIndex] = 0;\n }\n\n if (frontalState.transformationFlag !== 0) {\n // Prefront: find last appearance of each node\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n lastAppearanceCheck[nodeIndex] = 0;\n }\n\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n let reverseElementIndex = totalElements - elementIndex - 1;\n for (\n let localNodeIndex = 0;\n localNodeIndex < frontalState.nodesPerElement[reverseElementIndex];\n localNodeIndex++\n ) {\n let globalNodeIndex = frontalData.nodalNumbering[reverseElementIndex][localNodeIndex];\n if (lastAppearanceCheck[globalNodeIndex - 1] === 0) {\n lastAppearanceCheck[globalNodeIndex - 1] = 1;\n frontalData.nodalNumbering[reverseElementIndex][localNodeIndex] =\n -frontalData.nodalNumbering[reverseElementIndex][localNodeIndex];\n }\n }\n }\n }\n\n frontalState.transformationFlag = 0;\n let columnCount = 0;\n let rowCount = 0;\n\n for (let i = 0; i < systemSize; i++) {\n for (let j = 0; j < systemSize; j++) {\n frontMatrix[j][i] = 0;\n }\n }\n\n while (true) {\n // Assemble a new element only while we still have elements\n let assembled = false;\n let numElementNodes = 0;\n let numElementColumns = 0;\n\n if (elementData.currentElementIndex < totalElements) {\n elementData.currentElementIndex++;\n assembled = assembleElementContribution(meshData, FEAData, thermalBoundaryConditions, assembleFront);\n }\n\n if (assembled) {\n const currentElement = elementData.currentElementIndex;\n numElementNodes = frontalState.nodesPerElement[currentElement - 1];\n numElementColumns = frontalState.nodesPerElement[currentElement - 1];\n\n for (let localNodeIndex = 0; localNodeIndex < numElementColumns; localNodeIndex++) {\n let globalNodeIndex = frontalData.nodalNumbering[currentElement - 1][localNodeIndex];\n let columnIndex;\n\n if (columnCount === 0) {\n columnCount++;\n localDestination[localNodeIndex] = columnCount;\n frontStorage.columnHeaders[columnCount - 1] = globalNodeIndex;\n } else {\n for (columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n if (Math.abs(globalNodeIndex) === Math.abs(frontStorage.columnHeaders[columnIndex])) break;\n }\n\n if (columnIndex === columnCount) {\n columnCount++;\n localDestination[localNodeIndex] = columnCount;\n frontStorage.columnHeaders[columnCount - 1] = globalNodeIndex;\n } else {\n localDestination[localNodeIndex] = columnIndex + 1;\n frontStorage.columnHeaders[columnIndex] = globalNodeIndex;\n }\n }\n\n let rowIndex;\n if (rowCount === 0) {\n rowCount++;\n rowDestination[localNodeIndex] = rowCount;\n rowHeaders[rowCount - 1] = globalNodeIndex;\n } else {\n for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n if (Math.abs(globalNodeIndex) === Math.abs(rowHeaders[rowIndex])) break;\n }\n\n if (rowIndex === rowCount) {\n rowCount++;\n rowDestination[localNodeIndex] = rowCount;\n rowHeaders[rowCount - 1] = globalNodeIndex;\n } else {\n rowDestination[localNodeIndex] = rowIndex + 1;\n rowHeaders[rowIndex] = globalNodeIndex;\n }\n }\n }\n\n if (rowCount > systemSize || columnCount > systemSize) {\n errorLog(\"Error: systemSize not large enough\");\n return;\n }\n\n for (let localColumnIndex = 0; localColumnIndex < numElementColumns; localColumnIndex++) {\n let frontColumnIndex = localDestination[localColumnIndex];\n for (let localRowIndex = 0; localRowIndex < numElementNodes; localRowIndex++) {\n let frontRowIndex = rowDestination[localRowIndex];\n frontMatrix[frontRowIndex - 1][frontColumnIndex - 1] +=\n elementData.localJacobianMatrix[localRowIndex][localColumnIndex];\n }\n }\n }\n\n // Pivoting/elimination continues whether or not a new element was assembled\n let availableColumnCount = 0;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n if (frontStorage.columnHeaders[columnIndex] < 0) {\n pivotColumnIndices[availableColumnCount] = columnIndex + 1;\n availableColumnCount++;\n }\n }\n\n let constrainedRowCount = 0;\n let availableRowCount = 0;\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n let globalNodeIndex = rowHeaders[rowIndex];\n if (globalNodeIndex < 0) {\n pivotRowIndices[availableRowCount] = rowIndex + 1;\n availableRowCount++;\n let absoluteNodeIndex = Math.abs(globalNodeIndex);\n if (frontalData.nodeConstraintCode[absoluteNodeIndex - 1] === 1) {\n modifiedRows[constrainedRowCount] = rowIndex + 1;\n constrainedRowCount++;\n frontalData.nodeConstraintCode[absoluteNodeIndex - 1] = 2;\n frontalData.globalResidualVector[absoluteNodeIndex - 1] =\n frontalData.boundaryValues[absoluteNodeIndex - 1];\n }\n }\n }\n\n if (constrainedRowCount > 0) {\n for (let constrainedIndex = 0; constrainedIndex < constrainedRowCount; constrainedIndex++) {\n let rowIndex = modifiedRows[constrainedIndex] - 1;\n let globalNodeIndex = Math.abs(rowHeaders[rowIndex]);\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex][columnIndex] = 0;\n let columnGlobalIndex = Math.abs(frontStorage.columnHeaders[columnIndex]);\n if (columnGlobalIndex === globalNodeIndex) frontMatrix[rowIndex][columnIndex] = 1;\n }\n }\n }\n\n if (availableColumnCount > summedRows || elementData.currentElementIndex < totalElements) {\n if (availableColumnCount === 0) {\n errorLog(\"Error: no more rows fully summed\");\n return;\n }\n\n let pivotRowIndex = pivotRowIndices[0];\n let pivotColumnIndex = pivotColumnIndices[0];\n let pivotValue = frontMatrix[pivotRowIndex - 1][pivotColumnIndex - 1];\n\n if (Math.abs(pivotValue) < 1e-4) {\n pivotValue = 0;\n for (let columnIndex = 0; columnIndex < availableColumnCount; columnIndex++) {\n let testColumnIndex = pivotColumnIndices[columnIndex];\n for (let rowIndex = 0; rowIndex < availableRowCount; rowIndex++) {\n let testRowIndex = pivotRowIndices[rowIndex];\n let testValue = frontMatrix[testRowIndex - 1][testColumnIndex - 1];\n if (Math.abs(testValue) > Math.abs(pivotValue)) {\n pivotValue = testValue;\n pivotColumnIndex = testColumnIndex;\n pivotRowIndex = testRowIndex;\n }\n }\n }\n }\n\n let pivotGlobalRowIndex = Math.abs(rowHeaders[pivotRowIndex - 1]);\n pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[pivotColumnIndex - 1]); // Assign, don't declare\n let permutationHelper =\n pivotGlobalRowIndex +\n pivotColumnGlobalIndex +\n rowSwapCount[pivotGlobalRowIndex - 1] +\n columnSwapCount[pivotColumnGlobalIndex - 1];\n frontalState.determinant =\n (frontalState.determinant * pivotValue * (-1) ** permutationHelper) / Math.abs(pivotValue);\n\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n if (nodeIndex >= pivotGlobalRowIndex) rowSwapCount[nodeIndex]--;\n if (nodeIndex >= pivotColumnGlobalIndex) columnSwapCount[nodeIndex]--;\n }\n\n if (Math.abs(pivotValue) < 1e-10) {\n errorLog(\n `Matrix singular or ill-conditioned, currentElementIndex=${elementData.currentElementIndex}, pivotGlobalRowIndex=${pivotGlobalRowIndex}, pivotColumnGlobalIndex=${pivotColumnGlobalIndex}, pivotValue=${pivotValue}`\n );\n }\n\n if (pivotValue === 0) return;\n\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.pivotRow[columnIndex] = frontMatrix[pivotRowIndex - 1][columnIndex] / pivotValue;\n }\n\n let rightHandSide = frontalData.globalResidualVector[pivotGlobalRowIndex - 1] / pivotValue;\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] = rightHandSide;\n pivotColumn[pivotRowIndex - 1] = pivotValue;\n\n if (pivotRowIndex > 1) {\n for (let rowIndex = 0; rowIndex < pivotRowIndex - 1; rowIndex++) {\n let globalRowIndex = Math.abs(rowHeaders[rowIndex]);\n let eliminationFactor = frontMatrix[rowIndex][pivotColumnIndex - 1];\n pivotColumn[rowIndex] = eliminationFactor;\n if (pivotColumnIndex > 1 && eliminationFactor !== 0) {\n for (let columnIndex = 0; columnIndex < pivotColumnIndex - 1; columnIndex++) {\n frontMatrix[rowIndex][columnIndex] -= eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n if (pivotColumnIndex < columnCount) {\n for (let columnIndex = pivotColumnIndex; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex][columnIndex - 1] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n frontalData.globalResidualVector[globalRowIndex - 1] -= eliminationFactor * rightHandSide;\n }\n }\n\n if (pivotRowIndex < rowCount) {\n for (let rowIndex = pivotRowIndex; rowIndex < rowCount; rowIndex++) {\n let globalRowIndex = Math.abs(rowHeaders[rowIndex]);\n let eliminationFactor = frontMatrix[rowIndex][pivotColumnIndex - 1];\n pivotColumn[rowIndex] = eliminationFactor;\n if (pivotColumnIndex > 1) {\n for (let columnIndex = 0; columnIndex < pivotColumnIndex - 1; columnIndex++) {\n frontMatrix[rowIndex - 1][columnIndex] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n if (pivotColumnIndex < columnCount) {\n for (let columnIndex = pivotColumnIndex; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex - 1][columnIndex - 1] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n frontalData.globalResidualVector[globalRowIndex - 1] -= eliminationFactor * rightHandSide;\n }\n }\n\n for (let i = 0; i < rowCount; i++) {\n frontStorage.pivotData[pivotDataIndex + i - 1] = pivotColumn[i];\n }\n pivotDataIndex += rowCount;\n\n for (let i = 0; i < rowCount; i++) {\n frontStorage.pivotData[pivotDataIndex + i - 1] = rowHeaders[i];\n }\n pivotDataIndex += rowCount;\n\n frontStorage.pivotData[pivotDataIndex - 1] = pivotRowIndex;\n pivotDataIndex++;\n\n for (let i = 0; i < columnCount; i++) {\n frontStorage.frontValues[frontDataCounter - 1 + i] = frontStorage.pivotRow[i];\n }\n frontDataCounter += columnCount;\n\n for (let i = 0; i < columnCount; i++) {\n frontStorage.frontValues[frontDataCounter - 1 + i] = frontStorage.columnHeaders[i];\n }\n frontDataCounter += columnCount;\n\n frontStorage.frontValues[frontDataCounter - 1] = pivotGlobalRowIndex;\n frontStorage.frontValues[frontDataCounter] = columnCount;\n frontStorage.frontValues[frontDataCounter + 1] = pivotColumnIndex;\n frontStorage.frontValues[frontDataCounter + 2] = pivotValue;\n frontDataCounter += 4;\n\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n frontMatrix[rowIndex][columnCount - 1] = 0;\n }\n\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowCount - 1][columnIndex] = 0;\n }\n\n columnCount--;\n if (pivotColumnIndex < columnCount + 1) {\n for (let columnIndex = pivotColumnIndex - 1; columnIndex < columnCount; columnIndex++) {\n frontStorage.columnHeaders[columnIndex] = frontStorage.columnHeaders[columnIndex + 1];\n }\n }\n\n rowCount--;\n if (pivotRowIndex < rowCount + 1) {\n for (let rowIndex = pivotRowIndex - 1; rowIndex < rowCount; rowIndex++) {\n rowHeaders[rowIndex] = rowHeaders[rowIndex + 1];\n }\n }\n\n if (rowCount > 1 || elementData.currentElementIndex < totalElements) continue;\n\n pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[0]); // Assign, don't declare\n pivotRowIndex = 1;\n pivotValue = frontMatrix[0][0];\n pivotGlobalRowIndex = Math.abs(rowHeaders[0]);\n pivotColumnIndex = 1;\n permutationHelper =\n pivotGlobalRowIndex +\n pivotColumnGlobalIndex +\n rowSwapCount[pivotGlobalRowIndex - 1] +\n columnSwapCount[pivotColumnGlobalIndex - 1];\n frontalState.determinant =\n (frontalState.determinant * pivotValue * (-1) ** permutationHelper) / Math.abs(pivotValue);\n\n frontStorage.pivotRow[0] = 1;\n if (Math.abs(pivotValue) < 1e-10) {\n errorLog(\n `Matrix singular or ill-conditioned, currentElementIndex=${elementData.currentElementIndex}, pivotGlobalRowIndex=${pivotGlobalRowIndex}, pivotColumnGlobalIndex=${pivotColumnGlobalIndex}, pivotValue=${pivotValue}`\n );\n }\n\n if (pivotValue === 0) return;\n\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] =\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] / pivotValue;\n frontStorage.frontValues[frontDataCounter - 1] = frontStorage.pivotRow[0];\n frontDataCounter++;\n frontStorage.frontValues[frontDataCounter - 1] = frontStorage.columnHeaders[0];\n frontDataCounter++;\n frontStorage.frontValues[frontDataCounter - 1] = pivotGlobalRowIndex;\n frontStorage.frontValues[frontDataCounter] = columnCount;\n frontStorage.frontValues[frontDataCounter + 1] = pivotColumnIndex;\n frontStorage.frontValues[frontDataCounter + 2] = pivotValue;\n frontDataCounter += 4;\n\n frontStorage.pivotData[pivotDataIndex - 1] = pivotColumn[0];\n pivotDataIndex++;\n frontStorage.pivotData[pivotDataIndex - 1] = rowHeaders[0];\n pivotDataIndex++;\n frontStorage.pivotData[pivotDataIndex - 1] = pivotRowIndex;\n pivotDataIndex++;\n\n frontalState.frontDataIndex = frontDataCounter;\n if (frontalState.writeFlag === 1)\n debugLog(`total ecs transfer in matrix reduction=${frontDataCounter}`);\n\n // Back substitution\n performBackSubstitution(frontDataCounter);\n break;\n }\n }\n}\n\n/**\n * Function to perform back substitution for the frontal solver\n * @param {number} frontDataCounter - Index counter for the element contributions\n */\nfunction performBackSubstitution(frontDataCounter) {\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n frontalState.globalSolutionVector[nodeIndex] = frontalData.boundaryValues[nodeIndex];\n }\n\n for (let iterationIndex = 1; iterationIndex <= frontalState.totalNodes; iterationIndex++) {\n frontDataCounter -= 4;\n let pivotGlobalRowIndex = frontStorage.frontValues[frontDataCounter - 1];\n let columnCount = frontStorage.frontValues[frontDataCounter];\n let pivotColumnIndex = frontStorage.frontValues[frontDataCounter + 1];\n let pivotValue = frontStorage.frontValues[frontDataCounter + 2];\n\n if (iterationIndex === 1) {\n frontDataCounter--;\n frontStorage.columnHeaders[0] = frontStorage.frontValues[frontDataCounter - 1];\n frontDataCounter--;\n frontStorage.pivotRow[0] = frontStorage.frontValues[frontDataCounter - 1];\n } else {\n frontDataCounter -= columnCount;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.columnHeaders[columnIndex] =\n frontStorage.frontValues[frontDataCounter - 1 + columnIndex];\n }\n frontDataCounter -= columnCount;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.pivotRow[columnIndex] = frontStorage.frontValues[frontDataCounter - 1 + columnIndex];\n }\n }\n\n let pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[pivotColumnIndex - 1]);\n if (frontalData.nodeConstraintCode[pivotColumnGlobalIndex - 1] > 0) continue;\n\n let accumulatedValue = 0;\n frontStorage.pivotRow[pivotColumnIndex - 1] = 0;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n accumulatedValue -=\n frontStorage.pivotRow[columnIndex] *\n frontalState.globalSolutionVector[Math.abs(frontStorage.columnHeaders[columnIndex]) - 1];\n }\n\n frontalState.globalSolutionVector[pivotColumnGlobalIndex - 1] =\n accumulatedValue + frontalData.globalResidualVector[pivotGlobalRowIndex - 1];\n\n frontalData.nodeConstraintCode[pivotColumnGlobalIndex - 1] = 1;\n }\n\n if (frontalState.writeFlag === 1)\n debugLog(`value of frontDataCounter after backsubstitution=${frontDataCounter}`);\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 { runFrontalSolver } from \"./frontalSolverScript.js\";\nimport { assembleFrontPropagationFront } from \"../solvers/frontPropagationScript.js\";\n\n/**\n * Function to solve a system of non-linear equations using the Newton-Raphson method\n * @param {function} assembleMat - Matrix assembler based on the physical model\n * @param {object} context - Context object containing simulation data and options\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\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 // Check if using frontal solver\n if (context.solverMethod === \"frontal\") {\n const frontalResult = runFrontalSolver(\n assembleFrontPropagationFront,\n context.meshData,\n context.boundaryConditions,\n { solutionVector, eikonalActivationFlag: context.eikonalActivationFlag }\n );\n deltaX = frontalResult.solutionVector;\n } else {\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\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 { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { prepareMesh } from \"./mesh/meshUtilsScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleGeneralFormPDEMat, assembleGeneralFormPDEFront } from \"./solvers/generalFormPDEScript.js\";\nimport { assembleHeatConductionMat, assembleHeatConductionFront } from \"./solvers/heatConductionScript.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 this.coefficientFunctions = null; // Add storage for coefficient functions\n basicLog(\"FEAScriptModel instance created\");\n }\n\n /**\n * Sets the solver configuration\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} [options] - Optional additional configuration\n */\n setSolverConfig(solverConfig, options = {}) {\n this.solverConfig = solverConfig;\n\n // Store coefficient functions if provided\n if (options && options.coefficientFunctions) {\n this.coefficientFunctions = options.coefficientFunctions;\n debugLog(\"Coefficient functions set\");\n }\n\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 /**\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\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 === \"heatConductionScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Check if using frontal solver\n if (this.solverMethod === \"frontal\") {\n const frontalResult = runFrontalSolver(\n assembleHeatConductionFront,\n meshData,\n this.boundaryConditions\n );\n solutionVector = frontalResult.solutionVector;\n } else {\n // Use regular linear solver methods\n ({ jacobianMatrix, residualVector } = assembleHeatConductionMat(meshData, this.boundaryConditions));\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 } else if (this.solverConfig === \"generalFormPDEScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n // Check if using frontal solver\n if (this.solverMethod === \"frontal\") {\n errorLog(\n \"Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.\"\n );\n } else {\n // Use regular linear solver methods\n ({ jacobianMatrix, residualVector } = assembleGeneralFormPDEMat(\n meshData,\n this.boundaryConditions,\n this.coefficientFunctions\n ));\n\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\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 { initializeFEA, performIsoparametricMapping1D } from \"../mesh/meshUtilsScript.js\";\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the Jacobian matrix and residuals vector for the general form PDE model\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions\n * @param {object} coefficientFunctions - Functions A(x), B(x), C(x), D(x) for the PDE\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n */\nexport function assembleGeneralFormPDEMat(meshData, boundaryConditions, coefficientFunctions) {\n basicLog(\"Starting general form PDE 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 // Extract coefficient functions\n const { A, B, C, D } = coefficientFunctions;\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 if (meshDimension === \"1D\") {\n // 1D general form PDE\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 // Convert to 0-based indexing\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex = 0; gaussPointIndex < gaussPoints.length; gaussPointIndex++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < numNodes; i++) {\n xCoord += nodesXCoordinates[localToGlobalMap[i]] * basisFunction[i];\n }\n\n // Evaluate coefficient functions at this physical coordinate\n const a = A(xCoord);\n const b = B(xCoord);\n const c = C(xCoord);\n const d = D(xCoord);\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n const globalNodeIndex1 = localToGlobalMap[localNodeIndex1];\n\n // Source term contribution to residual vector\n residualVector[globalNodeIndex1] -=\n gaussWeights[gaussPointIndex] * detJacobian * d * basisFunction[localNodeIndex1];\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n const globalNodeIndex2 = localToGlobalMap[localNodeIndex2];\n\n // Diffusion term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n a *\n basisFunctionDerivX[localNodeIndex1] *\n basisFunctionDerivX[localNodeIndex2];\n\n // Advection term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n b *\n basisFunctionDerivX[localNodeIndex2] *\n basisFunction[localNodeIndex1];\n\n // Reaction term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n c *\n basisFunction[localNodeIndex1] *\n basisFunction[localNodeIndex2];\n }\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n errorLog(\"2D general form PDE is not yet supported in assembleGeneralFormPDEMat.\");\n // 2D general form PDE - empty for now\n }\n\n // Apply boundary conditions\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Apply Dirichlet boundary conditions only\n genericBoundaryConditions.imposeDirichletBoundaryConditions(residualVector, jacobianMatrix);\n\n basicLog(\"General form PDE matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n\n/**\n * Function to assemble the frontal solver matrix for the general form PDE model\n * @param {object} data - Object containing element data for the frontal solver\n * @returns {object} An object containing local Jacobian matrix and residual vector\n */\nexport function assembleGeneralFormPDEFront({\n elementIndex,\n nop,\n meshData,\n basisFunctions,\n FEAData,\n coefficientFunctions,\n}) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n const { A, B, C, D } = coefficientFunctions;\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n if (meshDimension === \"1D\") {\n // 1D general form PDE\n\n // Loop over Gauss points\n for (let gaussPointIndex = 0; gaussPointIndex < gaussPoints.length; gaussPointIndex++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < numNodes; i++) {\n xCoord += nodesXCoordinates[localToGlobalMap[i]] * basisFunction[i];\n }\n\n // Evaluate coefficient functions at this physical coordinate\n const a = A(xCoord);\n const b = B(xCoord);\n const c = C(xCoord);\n const d = D(xCoord);\n\n // Computation of local Jacobian matrix and residual vector\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n // Source term contribution to local residual vector\n localResidualVector[localNodeIndex1] -=\n gaussWeights[gaussPointIndex] * detJacobian * d * basisFunction[localNodeIndex1];\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n // Diffusion term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n a *\n basisFunctionDerivX[localNodeIndex1] *\n basisFunctionDerivX[localNodeIndex2];\n\n // Advection term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n b *\n basisFunctionDerivX[localNodeIndex2] *\n basisFunction[localNodeIndex1];\n\n // Reaction term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n c *\n basisFunction[localNodeIndex1] *\n basisFunction[localNodeIndex2];\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n errorLog(\"2D general form PDE is not yet supported in assembleGeneralFormPDEFront.\");\n // 2D general form PDE - empty for now\n }\n\n return {\n localJacobianMatrix,\n localResidualVector,\n ngl,\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 } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const printVersion = \"0.1.3\";"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","logSystem","level","console","log","basicLog","debugLog","message","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","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","nodesXCoordinates","totalNodesX","deltaX","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","meshData","totalNodes","colIndex","basisFunctions","gaussPointsAndWeights","localToGlobalMap","numNodes","performIsoparametricMapping1D","params","xCoordinates","ksiDerivX","localNodeIndex","detJacobian","basisFunctionDerivX","performIsoparametricMapping2D","yCoordinates","etaDerivX","ksiDerivY","etaDerivY","basisFunctionDerivY","ThermalBoundaryConditions","boundaryConditions","imposeConstantTempBoundaryConditions","Object","keys","boundaryKey","tempValue","globalNodeIndex","imposeConstantTempBoundaryConditionsFront","nodeConstraintCode","boundaryValues","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","basisFunctionsAndDerivatives","tangentVectorLength","localNodeIndex2","globalNodeIndex2","gaussPointIndex","imposeConvectionBoundaryConditionsFront","localJacobianMatrix","map","localResidualVector","boundaryElement","find","_","assembleHeatConductionFront","FEAData","ngl","gaussPointIndex1","localNodeIndex1","gaussPointIndex2","globalIndex","GenericBoundaryConditions","imposeDirichletBoundaryConditions","value","imposeConstantValueBoundaryConditionsFront","assembleFrontPropagationMat","eikonalActivationFlag","eikonalViscousTerm","totalElements","mappingResult","solutionDerivX","solutionDerivY","localToGlobalMap1","localToGlobalMap2","assembleFrontPropagationFront","frontalData","frontalState","elementData","currentElementIndex","frontStorage","runFrontalSolver","assembleFront","numElements","globalResidualVector","topologyData","lateralData","writeFlag","transformationFlag","nodesPerElement","determinant","systemSize","globalSolutionVector","frontDataIndex","frontSize","frontWidthEstimate","ceil","estimateFrontSize","frontValues","columnHeaders","pivotRow","pivotData","initializeFrontalArrays","dirichletBoundaryConditionsHandler","currentSolutionVector","thermalBoundaryConditions","pivotColumnGlobalIndex","localDestination","rowDestination","rowHeaders","pivotRowIndices","pivotColumnIndices","modifiedRows","pivotColumn","frontMatrix","rowSwapCount","columnSwapCount","lastAppearanceCheck","frontDataCounter","pivotDataIndex","summedRows","reverseElementIndex","columnCount","rowCount","assembled","numElementNodes","numElementColumns","assembleElementContribution","currentElement","columnIndex","rowIndex","localColumnIndex","frontColumnIndex","localRowIndex","availableColumnCount","constrainedRowCount","availableRowCount","absoluteNodeIndex","constrainedIndex","pivotRowIndex","pivotColumnIndex","pivotValue","testColumnIndex","testRowIndex","testValue","pivotGlobalRowIndex","permutationHelper","rightHandSide","globalRowIndex","eliminationFactor","performBackSubstitution","runFrontalAlgorithm","toExponential","finalNodesX","finalNodesY","slice","nodesCoordinates","boundaryLocalJacobianMatrix","boundaryResidualVector","isOnRobinTypeBoundary","some","result","localNodeI","localNodeJ","iterationIndex","accumulatedValue","newtonRaphson","assembleMat","context","errorNorm","initialSolution","Number","FEAScriptModel","solverConfig","meshConfig","coefficientFunctions","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","error","Error","mesh","nodesCoordinatesAndNumbering","prepareMesh","assembleHeatConductionMat","eikonalExteralIterations","newtonRaphsonResult","A","B","C","D","xCoord","a","b","d","globalNodeIndex1","assembleGeneralFormPDEMat","importGmshQuadTri","async","file","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","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","l","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","printVersion"],"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/mesh/basisFunctionsScript.js","../src/mesh/meshGenerationScript.js","../src/methods/numericalIntegrationScript.js","../src/mesh/meshUtilsScript.js","../src/solvers/thermalBoundaryConditionsScript.js","../src/solvers/heatConductionScript.js","../src/solvers/genericBoundaryConditionsScript.js","../src/solvers/frontPropagationScript.js","../src/methods/frontalSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/FEAScript.js","../src/solvers/generalFormPDEScript.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 printVersionInformation() {\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 errorLog(`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 { 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 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/**\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 * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\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 constant temperature boundary conditions for the frontal solver\n * @param {array} nodeConstraintCode - Array indicating boundary condition code for each node\n * @param {array} boundaryValues - Array containing boundary condition values\n */\n imposeConstantTempBoundaryConditionsFront(nodeConstraintCode, boundaryValues) {\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\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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 // 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 * Function to impose convection boundary conditions for the frontal solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @returns {object} An object containing:\n * - localJacobianMatrix: Local Jacobian matrix with convection contributions\n * - localResidualVector: Residual vector with convection contributions\n */\n imposeConvectionBoundaryConditionsFront(\n elementIndex,\n nodesXCoordinates,\n nodesYCoordinates,\n gaussPoints,\n gaussWeights,\n basisFunctions\n ) {\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 // Initialize local Jacobian matrix and local residual vector\n const numNodes = this.nop[elementIndex].length;\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Check if this element is on a convection boundary\n for (const boundaryKey in this.boundaryElements) {\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\n // Find if this element is on this boundary and which side\n const boundaryElement = this.boundaryElements[boundaryKey].find(\n ([elemIdx, _]) => elemIdx === elementIndex\n );\n\n if (boundaryElement) {\n const side = boundaryElement[1];\n\n if (this.meshDimension === \"1D\") {\n // Handle 1D case\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n nodeIndex = side === 0 ? 0 : 1;\n } else if (this.elementOrder === \"quadratic\") {\n nodeIndex = side === 0 ? 0 : 2;\n }\n\n // Add contribution to local Jacobian matrix and local residual vector\n debugLog(\n ` - Applied convection boundary condition to node ${nodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n localResidualVector[nodeIndex] += -convectionCoeff * extTemp;\n localJacobianMatrix[nodeIndex][nodeIndex] += convectionCoeff;\n } else if (this.meshDimension === \"2D\") {\n // Handle 2D case\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n\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 // Get basis functions\n const basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n const basisFunction = basisFunctionsAndDerivatives.basisFunction;\n const basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n const basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n // Calculate tangent vector components\n let ksiDerivX = 0,\n ksiDerivY = 0,\n etaDerivX = 0,\n etaDerivY = 0;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n } else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute tangent vector length\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 // Apply boundary conditions to local matrices\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n localResidualVector[localNodeIndex] +=\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 localJacobianMatrix[localNodeIndex][localNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n // Handle quadratic elements (similar pattern but with more Gauss points)\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n\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 // Apply boundary conditions to local matrices\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n localResidualVector[localNodeIndex] +=\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 localJacobianMatrix[localNodeIndex][localNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n }\n }\n }\n }\n\n return { localJacobianMatrix, localResidualVector };\n }\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 *\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\nexport function assembleHeatConductionMat(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 const 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 const 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 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\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\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 residual vector for the solid heat transfer model when using the frontal system solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nop - Nodal connectivity array (element-to-node mapping)\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @param {object} FEAData - Object containing FEA-related data\n * @returns {object} An object containing:\n * - localJacobianMatrix: Local Jacobian matrix\n * - localResidualVector: Residual vector contributions\n * - ngl: Array mapping local node indices to global node indices\n */\nexport function assembleHeatConductionFront({ elementIndex, nop, meshData, basisFunctions, FEAData }) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n // Loop over Gauss points\n if (meshDimension === \"1D\") {\n // 1D solid heat transfer\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n // 2D solid heat transfer\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } =\n basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1], gaussPoints[gaussPointIndex2]);\n\n // Create mapping from local element space to global mesh (convert to 0-based indexing)\n const localToGlobalMap = ngl.map((globalIndex) => globalIndex - 1);\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\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 return { localJacobianMatrix, localResidualVector, ngl };\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 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 Dirichlet boundary conditions\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n *\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\n imposeDirichletBoundaryConditions(residualVector, jacobianMatrix) {\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 value\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 value\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 value\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 value\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 * Function to impose constant value (Dirichlet) boundary conditions for the frontal solver\n * @param {array} nodeConstraintCode - Array indicating boundary condition code for each node\n * @param {array} boundaryValues - Array containing boundary condition values\n */\n imposeConstantValueBoundaryConditionsFront(nodeConstraintCode, boundaryValues) {\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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// Base viscous term that remains when eikonal equation is fully activated\nconst baseEikonalViscousTerm = 1e-2;\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 let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n debugLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n debugLog(`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 // Unsupported 1D front propagation\n errorLog(\"1D front propagation is not yet supported\");\n\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 // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // TODO 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 eikonalActivationFlag *\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 const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Dirichlet boundary conditions\n genericBoundaryConditions.imposeDirichletBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n\n/**\n * Function to assemble the local Jacobian matrix and residual vector for the front propagation model when using the frontal system solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nop - Nodal connectivity array (element-to-node mapping)\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @param {object} FEAData - Object containing FEA-related data\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 * - localJacobianMatrix: Local Jacobian matrix\n * - residualVector: Residual vector contributions\n * - ngl: Array mapping local node indices to global node indices\n */\nexport function assembleFrontPropagationFront({\n elementIndex,\n nop,\n meshData,\n basisFunctions,\n FEAData,\n solutionVector,\n eikonalActivationFlag,\n}) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n\n // Calculate eikonal viscous term\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(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 // Unsupported 1D front propagation\n errorLog(\"1D front propagation is not yet supported\");\n\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 // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // localJacobianMatrix\n // TODO localJacobianMatrix 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 // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } =\n basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1], gaussPoints[gaussPointIndex2]);\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\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 // Viscous term contribution\n localResidualVector[localNodeIndex1] +=\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 // Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n localResidualVector[localNodeIndex1] +=\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 // Viscous term contribution\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n\n // Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] +=\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 eikonalActivationFlag *\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 return { localJacobianMatrix, localResidualVector, ngl };\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 { initializeFEA } from \"../mesh/meshUtilsScript.js\";\nimport { assembleHeatConductionFront } from \"../solvers/heatConductionScript.js\";\nimport { ThermalBoundaryConditions } from \"../solvers/thermalBoundaryConditionsScript.js\";\nimport { assembleFrontPropagationFront } from \"../solvers/frontPropagationScript.js\";\nimport { GenericBoundaryConditions } from \"../solvers/genericBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// Create object templates\nconst frontalData = {};\nconst frontalState = {};\nconst elementData = { currentElementIndex: 0 };\nconst frontStorage = {};\nlet basisFunctions;\n\n/**\n * Function to run the frontal solver and obtain results for plotting\n * @param {function} assembleFront - Matrix assembler based on the physical model\n * @param {object} meshData - Object containing mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions\n * @param {object} [options] - Additional options for the solver\n * @returns {object} An object containing the solution vector and node coordinates\n */\nexport function runFrontalSolver(assembleFront, meshData, boundaryConditions, options = {}) {\n // Initialize FEA components\n const FEAData = initializeFEA(meshData);\n const totalNodes = meshData.nodesXCoordinates.length;\n const numElements = meshData.totalElements;\n const numNodes = FEAData.numNodes;\n\n // Calculate required array sizes\n initializeFrontalArrays(numNodes, numElements);\n\n // Start timing for system solving (frontal algorithm)\n basicLog(\"Solving system using frontal...\");\n console.time(\"systemSolving\");\n\n // Initialize basis functions\n basisFunctions = new BasisFunctions({\n meshDimension: meshData.meshDimension,\n elementOrder: meshData.elementOrder,\n });\n\n // Copy node connectivity array into frontalData storage\n for (let elementIndex = 0; elementIndex < meshData.totalElements; elementIndex++) {\n for (let nodeIndex = 0; nodeIndex < FEAData.numNodes; nodeIndex++) {\n frontalData.nodalNumbering[elementIndex][nodeIndex] = meshData.nop[elementIndex][nodeIndex];\n }\n }\n\n // Apply Dirichlet-type boundary conditions\n // Initialize all nodes with no boundary condition\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.nodeConstraintCode[nodeIndex] = 0;\n frontalData.boundaryValues[nodeIndex] = 0;\n }\n\n // Handle Dirichlet-type boundary conditions differently based on which solver is being used\n let dirichletBoundaryConditionsHandler;\n // Solid heat transfer model (heatConductionScript solver)\n if (assembleFront === assembleHeatConductionFront) {\n dirichletBoundaryConditionsHandler = new ThermalBoundaryConditions(\n boundaryConditions,\n meshData.boundaryElements,\n meshData.nop,\n meshData.meshDimension,\n meshData.elementOrder\n );\n\n dirichletBoundaryConditionsHandler.imposeConstantTempBoundaryConditionsFront(\n frontalData.nodeConstraintCode,\n frontalData.boundaryValues\n );\n // Front propagation model (frontPropagationScript solver)\n } else if (assembleFront === assembleFrontPropagationFront) {\n dirichletBoundaryConditionsHandler = new GenericBoundaryConditions(\n boundaryConditions,\n meshData.boundaryElements,\n meshData.nop,\n meshData.meshDimension,\n meshData.elementOrder\n );\n\n dirichletBoundaryConditionsHandler.imposeConstantValueBoundaryConditionsFront(\n frontalData.nodeConstraintCode,\n frontalData.boundaryValues\n );\n }\n // Initialize global residual vector\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.globalResidualVector[nodeIndex] = 0;\n }\n\n frontalState.totalNodes = meshData.nodesXCoordinates.length;\n frontalState.writeFlag = 0;\n frontalState.transformationFlag = 1;\n frontalState.determinant = 1;\n\n for (let elementIndex = 0; elementIndex < meshData.totalElements; elementIndex++) {\n frontalState.nodesPerElement[elementIndex] = FEAData.numNodes;\n }\n\n // Parameters for non-linear assemblers\n frontalState.currentSolutionVector = options.solutionVector;\n frontalState.eikonalActivationFlag = options.eikonalActivationFlag;\n\n // Pass assembleFront and dirichletBoundaryConditionsHandler to runFrontalAlgorithm\n runFrontalAlgorithm(meshData, FEAData, dirichletBoundaryConditionsHandler, assembleFront);\n\n // Copy solution\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.solutionVector[nodeIndex] = frontalState.globalSolutionVector[nodeIndex];\n }\n\n // Output results to console for debugging\n const { nodesXCoordinates, nodesYCoordinates } = meshData;\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n if (meshData.meshDimension === \"1D\") {\n // 1D case - only output X coordinates and temperature\n debugLog(\n `${nodesXCoordinates[nodeIndex].toExponential(5)} ${frontalData.solutionVector[\n nodeIndex\n ].toExponential(5)}`\n );\n } else {\n // 2D case - output X, Y coordinates and temperature\n debugLog(\n `${nodesXCoordinates[nodeIndex].toExponential(5)} ${nodesYCoordinates[nodeIndex].toExponential(\n 5\n )} ${frontalData.solutionVector[nodeIndex].toExponential(5)}`\n );\n }\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n const { nodesXCoordinates: finalNodesX, nodesYCoordinates: finalNodesY } = meshData;\n return {\n solutionVector: frontalData.solutionVector.slice(0, totalNodes),\n nodesCoordinates: {\n nodesXCoordinates: finalNodesX,\n nodesYCoordinates: finalNodesY,\n },\n };\n}\n\n/**\n * Function to initialize arrays dynamically based on problem size\n * @param {number} numNodes - Number of nodes per element\n * @param {number} numElements - Number of elements in the mesh\n */\nfunction initializeFrontalArrays(numNodes, numElements) {\n // Use the actual number of elements from the mesh\n frontalData.nodalNumbering = Array(numElements)\n .fill()\n .map(() => Array(numNodes).fill(0));\n frontalData.nodeConstraintCode = Array(numNodes).fill(0);\n frontalData.boundaryValues = Array(numNodes).fill(0);\n frontalData.globalResidualVector = Array(numNodes).fill(0);\n frontalData.solutionVector = Array(numNodes).fill(0);\n frontalData.topologyData = Array(numElements).fill(0);\n frontalData.lateralData = Array(numElements).fill(0);\n\n // Initialize frontalState arrays\n frontalState.writeFlag = 0;\n frontalState.totalNodes = numNodes;\n frontalState.transformationFlag = 0;\n frontalState.nodesPerElement = Array(numElements).fill(0);\n frontalState.determinant = 1;\n\n // For matrix operations, estimate required size based on problem complexity\n const systemSize = Math.max(numNodes, 2000);\n frontalState.globalSolutionVector = Array(systemSize).fill(0);\n frontalState.frontDataIndex = 0;\n\n // Initialize elementData arrays\n elementData.localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n elementData.currentElementIndex = 0;\n\n // Initialize frontStorage arrays\n const frontSize = estimateFrontSize(numNodes, numElements);\n frontStorage.frontValues = Array(frontSize).fill(0);\n frontStorage.columnHeaders = Array(systemSize).fill(0);\n frontStorage.pivotRow = Array(systemSize).fill(0);\n frontStorage.pivotData = Array(frontSize).fill(0);\n}\n\n/**\n * Function to estimate the required front size\n * @param {number} numNodes - Number of of nodes per element\n * @param {number} numElements - Number of elements in the mesh\n * @returns {number} Estimated front size\n */\nfunction estimateFrontSize(numNodes, numElements) {\n const frontWidthEstimate = Math.max(Math.ceil(Math.sqrt(numElements)) * numNodes, numNodes * 2);\n return frontWidthEstimate * numElements;\n}\n// Old function to estimate the required front size\n// function estimateFrontSize(numNodes, numElements, numNodes) {\n// const frontWidthEstimate = Math.ceil(Math.sqrt(numElements) * numNodes * 2);\n// const frontSize = frontWidthEstimate * numNodes * 4;\n// return Math.max(frontSize, 10000);\n// }\n\n/**\n * Function to compute local Jacobian matrix and local residual vector\n * @param {object} meshData - Object containing mesh data\n * @param {object} FEAData - Object containing FEA-related data\n * @param {object} thermalBoundaryConditions - Object containing thermal boundary conditions\n * @param {function} assembleFront - Matrix assembler based on the physical model\n */\nfunction assembleElementContribution(meshData, FEAData, thermalBoundaryConditions, assembleFront) {\n const elementIndex = elementData.currentElementIndex - 1;\n\n // Guard against out-of-range indices\n if (elementIndex < 0 || elementIndex >= meshData.totalElements) {\n errorLog(`Skipping out-of-range elementIndex=${elementIndex} (totalElements=${meshData.totalElements})`);\n return false;\n }\n\n // Domain terms\n const { localJacobianMatrix, localResidualVector, ngl } = assembleFront({\n elementIndex,\n nop: frontalData.nodalNumbering,\n meshData,\n basisFunctions: basisFunctions,\n FEAData,\n // These are ignored by linear assemblers\n solutionVector: frontalState.currentSolutionVector,\n eikonalActivationFlag: frontalState.eikonalActivationFlag,\n });\n\n // Handle Robin-type boundary conditions differently based on which solver is being used\n let boundaryLocalJacobianMatrix = Array(FEAData.numNodes)\n .fill()\n .map(() => Array(FEAData.numNodes).fill(0));\n let boundaryResidualVector = Array(FEAData.numNodes).fill(0);\n\n // heatConductionScript solver\n if (assembleFront === assembleHeatConductionFront) {\n // Check if this element is on a Robin-type boundary\n let isOnRobinTypeBoundary = false;\n for (const boundaryKey in meshData.boundaryElements) {\n if (\n thermalBoundaryConditions.boundaryConditions[boundaryKey]?.[0] === \"convection\" &&\n meshData.boundaryElements[boundaryKey].some(([elemIdx, _]) => elemIdx === elementIndex)\n ) {\n isOnRobinTypeBoundary = true;\n break;\n }\n }\n\n // Only calculate Robin-type for elements when required\n if (isOnRobinTypeBoundary) {\n const { gaussPoints, gaussWeights } = FEAData;\n const result = thermalBoundaryConditions.imposeConvectionBoundaryConditionsFront(\n elementIndex,\n meshData.nodesXCoordinates,\n meshData.nodesYCoordinates,\n gaussPoints,\n gaussWeights,\n basisFunctions\n );\n boundaryLocalJacobianMatrix = result.localJacobianMatrix;\n boundaryResidualVector = result.localResidualVector;\n }\n } else if (assembleFront === assembleFrontPropagationFront) {\n // For now, no Robin-type boundary conditions exist for any other solver\n }\n\n // Combine domain and boundary contributions\n for (let localNodeI = 0; localNodeI < FEAData.numNodes; localNodeI++) {\n for (let localNodeJ = 0; localNodeJ < FEAData.numNodes; localNodeJ++) {\n elementData.localJacobianMatrix[localNodeI][localNodeJ] =\n localJacobianMatrix[localNodeI][localNodeJ] + boundaryLocalJacobianMatrix[localNodeI][localNodeJ];\n }\n }\n\n // Assemble local element residual\n for (let localNodeIndex = 0; localNodeIndex < FEAData.numNodes; localNodeIndex++) {\n const globalNodeIndex = ngl[localNodeIndex] - 1;\n frontalData.globalResidualVector[globalNodeIndex] +=\n localResidualVector[localNodeIndex] + boundaryResidualVector[localNodeIndex];\n }\n\n return true;\n}\n\n/**\n * Function to implement the frontal solver algorithm\n * @param {object} meshData - Object containing mesh data\n * @param {object} FEAData - Object containing FEA-related data\n * @param {object} thermalBoundaryConditions - Object containing thermal boundary conditions\n * @param {function} assembleFront - Matrix assembler based on the physical model\n */\nfunction runFrontalAlgorithm(meshData, FEAData, thermalBoundaryConditions, assembleFront) {\n // Allocate local arrays dynamically\n const totalElements = meshData.totalElements;\n const numNodes = meshData.nodesXCoordinates.length;\n const systemSize = Math.max(numNodes, frontalState.globalSolutionVector.length);\n let localDestination = Array(FEAData.numNodes).fill(0);\n let rowDestination = Array(FEAData.numNodes).fill(0);\n let rowHeaders = Array(systemSize).fill(0);\n let pivotRowIndices = Array(systemSize).fill(0);\n let pivotColumnIndices = Array(systemSize).fill(0);\n let modifiedRows = Array(systemSize).fill(0);\n let pivotColumn = Array(systemSize).fill(0);\n let frontMatrix = Array(systemSize)\n .fill()\n .map(() => Array(systemSize).fill(0));\n let rowSwapCount = Array(numNodes).fill(0);\n let columnSwapCount = Array(numNodes).fill(0);\n let lastAppearanceCheck = Array(numNodes).fill(0);\n let pivotColumnGlobalIndex; // Pivot column global index\n\n let frontDataCounter = 1;\n frontalState.writeFlag++;\n let pivotDataIndex = 1;\n let summedRows = 1;\n elementData.currentElementIndex = 0;\n\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n rowSwapCount[nodeIndex] = 0;\n columnSwapCount[nodeIndex] = 0;\n }\n\n if (frontalState.transformationFlag !== 0) {\n // Prefront: find last appearance of each node\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n lastAppearanceCheck[nodeIndex] = 0;\n }\n\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n let reverseElementIndex = totalElements - elementIndex - 1;\n for (\n let localNodeIndex = 0;\n localNodeIndex < frontalState.nodesPerElement[reverseElementIndex];\n localNodeIndex++\n ) {\n let globalNodeIndex = frontalData.nodalNumbering[reverseElementIndex][localNodeIndex];\n if (lastAppearanceCheck[globalNodeIndex - 1] === 0) {\n lastAppearanceCheck[globalNodeIndex - 1] = 1;\n frontalData.nodalNumbering[reverseElementIndex][localNodeIndex] =\n -frontalData.nodalNumbering[reverseElementIndex][localNodeIndex];\n }\n }\n }\n }\n\n frontalState.transformationFlag = 0;\n let columnCount = 0;\n let rowCount = 0;\n\n for (let i = 0; i < systemSize; i++) {\n for (let j = 0; j < systemSize; j++) {\n frontMatrix[j][i] = 0;\n }\n }\n\n while (true) {\n // Assemble a new element only while we still have elements\n let assembled = false;\n let numElementNodes = 0;\n let numElementColumns = 0;\n\n if (elementData.currentElementIndex < totalElements) {\n elementData.currentElementIndex++;\n assembled = assembleElementContribution(meshData, FEAData, thermalBoundaryConditions, assembleFront);\n }\n\n if (assembled) {\n const currentElement = elementData.currentElementIndex;\n numElementNodes = frontalState.nodesPerElement[currentElement - 1];\n numElementColumns = frontalState.nodesPerElement[currentElement - 1];\n\n for (let localNodeIndex = 0; localNodeIndex < numElementColumns; localNodeIndex++) {\n let globalNodeIndex = frontalData.nodalNumbering[currentElement - 1][localNodeIndex];\n let columnIndex;\n\n if (columnCount === 0) {\n columnCount++;\n localDestination[localNodeIndex] = columnCount;\n frontStorage.columnHeaders[columnCount - 1] = globalNodeIndex;\n } else {\n for (columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n if (Math.abs(globalNodeIndex) === Math.abs(frontStorage.columnHeaders[columnIndex])) break;\n }\n\n if (columnIndex === columnCount) {\n columnCount++;\n localDestination[localNodeIndex] = columnCount;\n frontStorage.columnHeaders[columnCount - 1] = globalNodeIndex;\n } else {\n localDestination[localNodeIndex] = columnIndex + 1;\n frontStorage.columnHeaders[columnIndex] = globalNodeIndex;\n }\n }\n\n let rowIndex;\n if (rowCount === 0) {\n rowCount++;\n rowDestination[localNodeIndex] = rowCount;\n rowHeaders[rowCount - 1] = globalNodeIndex;\n } else {\n for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n if (Math.abs(globalNodeIndex) === Math.abs(rowHeaders[rowIndex])) break;\n }\n\n if (rowIndex === rowCount) {\n rowCount++;\n rowDestination[localNodeIndex] = rowCount;\n rowHeaders[rowCount - 1] = globalNodeIndex;\n } else {\n rowDestination[localNodeIndex] = rowIndex + 1;\n rowHeaders[rowIndex] = globalNodeIndex;\n }\n }\n }\n\n if (rowCount > systemSize || columnCount > systemSize) {\n errorLog(\"Error: systemSize not large enough\");\n return;\n }\n\n for (let localColumnIndex = 0; localColumnIndex < numElementColumns; localColumnIndex++) {\n let frontColumnIndex = localDestination[localColumnIndex];\n for (let localRowIndex = 0; localRowIndex < numElementNodes; localRowIndex++) {\n let frontRowIndex = rowDestination[localRowIndex];\n frontMatrix[frontRowIndex - 1][frontColumnIndex - 1] +=\n elementData.localJacobianMatrix[localRowIndex][localColumnIndex];\n }\n }\n }\n\n // Pivoting/elimination continues whether or not a new element was assembled\n let availableColumnCount = 0;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n if (frontStorage.columnHeaders[columnIndex] < 0) {\n pivotColumnIndices[availableColumnCount] = columnIndex + 1;\n availableColumnCount++;\n }\n }\n\n let constrainedRowCount = 0;\n let availableRowCount = 0;\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n let globalNodeIndex = rowHeaders[rowIndex];\n if (globalNodeIndex < 0) {\n pivotRowIndices[availableRowCount] = rowIndex + 1;\n availableRowCount++;\n let absoluteNodeIndex = Math.abs(globalNodeIndex);\n if (frontalData.nodeConstraintCode[absoluteNodeIndex - 1] === 1) {\n modifiedRows[constrainedRowCount] = rowIndex + 1;\n constrainedRowCount++;\n frontalData.nodeConstraintCode[absoluteNodeIndex - 1] = 2;\n frontalData.globalResidualVector[absoluteNodeIndex - 1] =\n frontalData.boundaryValues[absoluteNodeIndex - 1];\n }\n }\n }\n\n if (constrainedRowCount > 0) {\n for (let constrainedIndex = 0; constrainedIndex < constrainedRowCount; constrainedIndex++) {\n let rowIndex = modifiedRows[constrainedIndex] - 1;\n let globalNodeIndex = Math.abs(rowHeaders[rowIndex]);\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex][columnIndex] = 0;\n let columnGlobalIndex = Math.abs(frontStorage.columnHeaders[columnIndex]);\n if (columnGlobalIndex === globalNodeIndex) frontMatrix[rowIndex][columnIndex] = 1;\n }\n }\n }\n\n if (availableColumnCount > summedRows || elementData.currentElementIndex < totalElements) {\n if (availableColumnCount === 0) {\n errorLog(\"Error: no more rows fully summed\");\n return;\n }\n\n let pivotRowIndex = pivotRowIndices[0];\n let pivotColumnIndex = pivotColumnIndices[0];\n let pivotValue = frontMatrix[pivotRowIndex - 1][pivotColumnIndex - 1];\n\n if (Math.abs(pivotValue) < 1e-4) {\n pivotValue = 0;\n for (let columnIndex = 0; columnIndex < availableColumnCount; columnIndex++) {\n let testColumnIndex = pivotColumnIndices[columnIndex];\n for (let rowIndex = 0; rowIndex < availableRowCount; rowIndex++) {\n let testRowIndex = pivotRowIndices[rowIndex];\n let testValue = frontMatrix[testRowIndex - 1][testColumnIndex - 1];\n if (Math.abs(testValue) > Math.abs(pivotValue)) {\n pivotValue = testValue;\n pivotColumnIndex = testColumnIndex;\n pivotRowIndex = testRowIndex;\n }\n }\n }\n }\n\n let pivotGlobalRowIndex = Math.abs(rowHeaders[pivotRowIndex - 1]);\n pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[pivotColumnIndex - 1]); // Assign, don't declare\n let permutationHelper =\n pivotGlobalRowIndex +\n pivotColumnGlobalIndex +\n rowSwapCount[pivotGlobalRowIndex - 1] +\n columnSwapCount[pivotColumnGlobalIndex - 1];\n frontalState.determinant =\n (frontalState.determinant * pivotValue * (-1) ** permutationHelper) / Math.abs(pivotValue);\n\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n if (nodeIndex >= pivotGlobalRowIndex) rowSwapCount[nodeIndex]--;\n if (nodeIndex >= pivotColumnGlobalIndex) columnSwapCount[nodeIndex]--;\n }\n\n if (Math.abs(pivotValue) < 1e-10) {\n errorLog(\n `Matrix singular or ill-conditioned, currentElementIndex=${elementData.currentElementIndex}, pivotGlobalRowIndex=${pivotGlobalRowIndex}, pivotColumnGlobalIndex=${pivotColumnGlobalIndex}, pivotValue=${pivotValue}`\n );\n }\n\n if (pivotValue === 0) return;\n\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.pivotRow[columnIndex] = frontMatrix[pivotRowIndex - 1][columnIndex] / pivotValue;\n }\n\n let rightHandSide = frontalData.globalResidualVector[pivotGlobalRowIndex - 1] / pivotValue;\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] = rightHandSide;\n pivotColumn[pivotRowIndex - 1] = pivotValue;\n\n if (pivotRowIndex > 1) {\n for (let rowIndex = 0; rowIndex < pivotRowIndex - 1; rowIndex++) {\n let globalRowIndex = Math.abs(rowHeaders[rowIndex]);\n let eliminationFactor = frontMatrix[rowIndex][pivotColumnIndex - 1];\n pivotColumn[rowIndex] = eliminationFactor;\n if (pivotColumnIndex > 1 && eliminationFactor !== 0) {\n for (let columnIndex = 0; columnIndex < pivotColumnIndex - 1; columnIndex++) {\n frontMatrix[rowIndex][columnIndex] -= eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n if (pivotColumnIndex < columnCount) {\n for (let columnIndex = pivotColumnIndex; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex][columnIndex - 1] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n frontalData.globalResidualVector[globalRowIndex - 1] -= eliminationFactor * rightHandSide;\n }\n }\n\n if (pivotRowIndex < rowCount) {\n for (let rowIndex = pivotRowIndex; rowIndex < rowCount; rowIndex++) {\n let globalRowIndex = Math.abs(rowHeaders[rowIndex]);\n let eliminationFactor = frontMatrix[rowIndex][pivotColumnIndex - 1];\n pivotColumn[rowIndex] = eliminationFactor;\n if (pivotColumnIndex > 1) {\n for (let columnIndex = 0; columnIndex < pivotColumnIndex - 1; columnIndex++) {\n frontMatrix[rowIndex - 1][columnIndex] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n if (pivotColumnIndex < columnCount) {\n for (let columnIndex = pivotColumnIndex; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex - 1][columnIndex - 1] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n frontalData.globalResidualVector[globalRowIndex - 1] -= eliminationFactor * rightHandSide;\n }\n }\n\n for (let i = 0; i < rowCount; i++) {\n frontStorage.pivotData[pivotDataIndex + i - 1] = pivotColumn[i];\n }\n pivotDataIndex += rowCount;\n\n for (let i = 0; i < rowCount; i++) {\n frontStorage.pivotData[pivotDataIndex + i - 1] = rowHeaders[i];\n }\n pivotDataIndex += rowCount;\n\n frontStorage.pivotData[pivotDataIndex - 1] = pivotRowIndex;\n pivotDataIndex++;\n\n for (let i = 0; i < columnCount; i++) {\n frontStorage.frontValues[frontDataCounter - 1 + i] = frontStorage.pivotRow[i];\n }\n frontDataCounter += columnCount;\n\n for (let i = 0; i < columnCount; i++) {\n frontStorage.frontValues[frontDataCounter - 1 + i] = frontStorage.columnHeaders[i];\n }\n frontDataCounter += columnCount;\n\n frontStorage.frontValues[frontDataCounter - 1] = pivotGlobalRowIndex;\n frontStorage.frontValues[frontDataCounter] = columnCount;\n frontStorage.frontValues[frontDataCounter + 1] = pivotColumnIndex;\n frontStorage.frontValues[frontDataCounter + 2] = pivotValue;\n frontDataCounter += 4;\n\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n frontMatrix[rowIndex][columnCount - 1] = 0;\n }\n\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowCount - 1][columnIndex] = 0;\n }\n\n columnCount--;\n if (pivotColumnIndex < columnCount + 1) {\n for (let columnIndex = pivotColumnIndex - 1; columnIndex < columnCount; columnIndex++) {\n frontStorage.columnHeaders[columnIndex] = frontStorage.columnHeaders[columnIndex + 1];\n }\n }\n\n rowCount--;\n if (pivotRowIndex < rowCount + 1) {\n for (let rowIndex = pivotRowIndex - 1; rowIndex < rowCount; rowIndex++) {\n rowHeaders[rowIndex] = rowHeaders[rowIndex + 1];\n }\n }\n\n if (rowCount > 1 || elementData.currentElementIndex < totalElements) continue;\n\n pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[0]); // Assign, don't declare\n pivotRowIndex = 1;\n pivotValue = frontMatrix[0][0];\n pivotGlobalRowIndex = Math.abs(rowHeaders[0]);\n pivotColumnIndex = 1;\n permutationHelper =\n pivotGlobalRowIndex +\n pivotColumnGlobalIndex +\n rowSwapCount[pivotGlobalRowIndex - 1] +\n columnSwapCount[pivotColumnGlobalIndex - 1];\n frontalState.determinant =\n (frontalState.determinant * pivotValue * (-1) ** permutationHelper) / Math.abs(pivotValue);\n\n frontStorage.pivotRow[0] = 1;\n if (Math.abs(pivotValue) < 1e-10) {\n errorLog(\n `Matrix singular or ill-conditioned, currentElementIndex=${elementData.currentElementIndex}, pivotGlobalRowIndex=${pivotGlobalRowIndex}, pivotColumnGlobalIndex=${pivotColumnGlobalIndex}, pivotValue=${pivotValue}`\n );\n }\n\n if (pivotValue === 0) return;\n\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] =\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] / pivotValue;\n frontStorage.frontValues[frontDataCounter - 1] = frontStorage.pivotRow[0];\n frontDataCounter++;\n frontStorage.frontValues[frontDataCounter - 1] = frontStorage.columnHeaders[0];\n frontDataCounter++;\n frontStorage.frontValues[frontDataCounter - 1] = pivotGlobalRowIndex;\n frontStorage.frontValues[frontDataCounter] = columnCount;\n frontStorage.frontValues[frontDataCounter + 1] = pivotColumnIndex;\n frontStorage.frontValues[frontDataCounter + 2] = pivotValue;\n frontDataCounter += 4;\n\n frontStorage.pivotData[pivotDataIndex - 1] = pivotColumn[0];\n pivotDataIndex++;\n frontStorage.pivotData[pivotDataIndex - 1] = rowHeaders[0];\n pivotDataIndex++;\n frontStorage.pivotData[pivotDataIndex - 1] = pivotRowIndex;\n pivotDataIndex++;\n\n frontalState.frontDataIndex = frontDataCounter;\n if (frontalState.writeFlag === 1)\n debugLog(`total ecs transfer in matrix reduction=${frontDataCounter}`);\n\n // Back substitution\n performBackSubstitution(frontDataCounter);\n break;\n }\n }\n}\n\n/**\n * Function to perform back substitution for the frontal solver\n * @param {number} frontDataCounter - Index counter for the element contributions\n */\nfunction performBackSubstitution(frontDataCounter) {\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n frontalState.globalSolutionVector[nodeIndex] = frontalData.boundaryValues[nodeIndex];\n }\n\n for (let iterationIndex = 1; iterationIndex <= frontalState.totalNodes; iterationIndex++) {\n frontDataCounter -= 4;\n let pivotGlobalRowIndex = frontStorage.frontValues[frontDataCounter - 1];\n let columnCount = frontStorage.frontValues[frontDataCounter];\n let pivotColumnIndex = frontStorage.frontValues[frontDataCounter + 1];\n let pivotValue = frontStorage.frontValues[frontDataCounter + 2];\n\n if (iterationIndex === 1) {\n frontDataCounter--;\n frontStorage.columnHeaders[0] = frontStorage.frontValues[frontDataCounter - 1];\n frontDataCounter--;\n frontStorage.pivotRow[0] = frontStorage.frontValues[frontDataCounter - 1];\n } else {\n frontDataCounter -= columnCount;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.columnHeaders[columnIndex] =\n frontStorage.frontValues[frontDataCounter - 1 + columnIndex];\n }\n frontDataCounter -= columnCount;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.pivotRow[columnIndex] = frontStorage.frontValues[frontDataCounter - 1 + columnIndex];\n }\n }\n\n let pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[pivotColumnIndex - 1]);\n if (frontalData.nodeConstraintCode[pivotColumnGlobalIndex - 1] > 0) continue;\n\n let accumulatedValue = 0;\n frontStorage.pivotRow[pivotColumnIndex - 1] = 0;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n accumulatedValue -=\n frontStorage.pivotRow[columnIndex] *\n frontalState.globalSolutionVector[Math.abs(frontStorage.columnHeaders[columnIndex]) - 1];\n }\n\n frontalState.globalSolutionVector[pivotColumnGlobalIndex - 1] =\n accumulatedValue + frontalData.globalResidualVector[pivotGlobalRowIndex - 1];\n\n frontalData.nodeConstraintCode[pivotColumnGlobalIndex - 1] = 1;\n }\n\n if (frontalState.writeFlag === 1)\n debugLog(`value of frontDataCounter after backsubstitution=${frontDataCounter}`);\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 { runFrontalSolver } from \"./frontalSolverScript.js\";\nimport { assembleFrontPropagationFront } from \"../solvers/frontPropagationScript.js\";\n\n/**\n * Function to solve a system of non-linear equations using the Newton-Raphson method\n * @param {function} assembleMat - Matrix assembler based on the physical model\n * @param {object} context - Context object containing simulation data and options\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\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 // Check if using frontal solver\n if (context.solverMethod === \"frontal\") {\n const frontalResult = runFrontalSolver(\n assembleFrontPropagationFront,\n context.meshData,\n context.boundaryConditions,\n { solutionVector, eikonalActivationFlag: context.eikonalActivationFlag }\n );\n deltaX = frontalResult.solutionVector;\n } else {\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\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 { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { prepareMesh } from \"./mesh/meshUtilsScript.js\";\nimport { assembleFrontPropagationMat } from \"./solvers/frontPropagationScript.js\";\nimport { assembleGeneralFormPDEMat, assembleGeneralFormPDEFront } from \"./solvers/generalFormPDEScript.js\";\nimport { assembleHeatConductionMat, assembleHeatConductionFront } from \"./solvers/heatConductionScript.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 this.coefficientFunctions = null; // Add storage for coefficient functions\n basicLog(\"FEAScriptModel instance created\");\n }\n\n /**\n * Sets the solver configuration\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} [options] - Optional additional configuration\n */\n setSolverConfig(solverConfig, options = {}) {\n this.solverConfig = solverConfig;\n\n // Store coefficient functions if provided\n if (options && options.coefficientFunctions) {\n this.coefficientFunctions = options.coefficientFunctions;\n debugLog(\"Coefficient functions set\");\n }\n\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 /**\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\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 === \"heatConductionScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Check if using frontal solver\n if (this.solverMethod === \"frontal\") {\n const frontalResult = runFrontalSolver(\n assembleHeatConductionFront,\n meshData,\n this.boundaryConditions\n );\n solutionVector = frontalResult.solutionVector;\n } else {\n // Use regular linear solver methods\n ({ jacobianMatrix, residualVector } = assembleHeatConductionMat(meshData, this.boundaryConditions));\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 } else if (this.solverConfig === \"generalFormPDEScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n // Check if using frontal solver\n if (this.solverMethod === \"frontal\") {\n errorLog(\n \"Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.\"\n );\n } else {\n // Use regular linear solver methods\n ({ jacobianMatrix, residualVector } = assembleGeneralFormPDEMat(\n meshData,\n this.boundaryConditions,\n this.coefficientFunctions\n ));\n\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\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 { initializeFEA, performIsoparametricMapping1D } from \"../mesh/meshUtilsScript.js\";\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the Jacobian matrix and residuals vector for the general form PDE model\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions\n * @param {object} coefficientFunctions - Functions A(x), B(x), C(x), D(x) for the PDE\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n */\nexport function assembleGeneralFormPDEMat(meshData, boundaryConditions, coefficientFunctions) {\n basicLog(\"Starting general form PDE 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 // Extract coefficient functions\n const { A, B, C, D } = coefficientFunctions;\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 if (meshDimension === \"1D\") {\n // 1D general form PDE\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 // Convert to 0-based indexing\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex = 0; gaussPointIndex < gaussPoints.length; gaussPointIndex++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < numNodes; i++) {\n xCoord += nodesXCoordinates[localToGlobalMap[i]] * basisFunction[i];\n }\n\n // Evaluate coefficient functions at this physical coordinate\n const a = A(xCoord);\n const b = B(xCoord);\n const c = C(xCoord);\n const d = D(xCoord);\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n const globalNodeIndex1 = localToGlobalMap[localNodeIndex1];\n\n // Source term contribution to residual vector\n residualVector[globalNodeIndex1] -=\n gaussWeights[gaussPointIndex] * detJacobian * d * basisFunction[localNodeIndex1];\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n const globalNodeIndex2 = localToGlobalMap[localNodeIndex2];\n\n // Diffusion term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n a *\n basisFunctionDerivX[localNodeIndex1] *\n basisFunctionDerivX[localNodeIndex2];\n\n // Advection term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n b *\n basisFunctionDerivX[localNodeIndex2] *\n basisFunction[localNodeIndex1];\n\n // Reaction term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n c *\n basisFunction[localNodeIndex1] *\n basisFunction[localNodeIndex2];\n }\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n errorLog(\"2D general form PDE is not yet supported in assembleGeneralFormPDEMat.\");\n // 2D general form PDE - empty for now\n }\n\n // Apply boundary conditions\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Apply Dirichlet boundary conditions only\n genericBoundaryConditions.imposeDirichletBoundaryConditions(residualVector, jacobianMatrix);\n\n basicLog(\"General form PDE matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n\n/**\n * Function to assemble the frontal solver matrix for the general form PDE model\n * @param {object} data - Object containing element data for the frontal solver\n * @returns {object} An object containing local Jacobian matrix and residual vector\n */\nexport function assembleGeneralFormPDEFront({\n elementIndex,\n nop,\n meshData,\n basisFunctions,\n FEAData,\n coefficientFunctions,\n}) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n const { A, B, C, D } = coefficientFunctions;\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n if (meshDimension === \"1D\") {\n // 1D general form PDE\n\n // Loop over Gauss points\n for (let gaussPointIndex = 0; gaussPointIndex < gaussPoints.length; gaussPointIndex++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < numNodes; i++) {\n xCoord += nodesXCoordinates[localToGlobalMap[i]] * basisFunction[i];\n }\n\n // Evaluate coefficient functions at this physical coordinate\n const a = A(xCoord);\n const b = B(xCoord);\n const c = C(xCoord);\n const d = D(xCoord);\n\n // Computation of local Jacobian matrix and residual vector\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n // Source term contribution to local residual vector\n localResidualVector[localNodeIndex1] -=\n gaussWeights[gaussPointIndex] * detJacobian * d * basisFunction[localNodeIndex1];\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n // Diffusion term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n a *\n basisFunctionDerivX[localNodeIndex1] *\n basisFunctionDerivX[localNodeIndex2];\n\n // Advection term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n b *\n basisFunctionDerivX[localNodeIndex2] *\n basisFunction[localNodeIndex1];\n\n // Reaction term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n c *\n basisFunction[localNodeIndex1] *\n basisFunction[localNodeIndex2];\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n errorLog(\"2D general form PDE is not yet supported in assembleGeneralFormPDEFront.\");\n // 2D general form PDE - empty for now\n }\n\n return {\n localJacobianMatrix,\n localResidualVector,\n ngl,\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 } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const printVersion = \"0.1.3\";"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","logSystem","level","console","log","basicLog","debugLog","message","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","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","nodesXCoordinates","totalNodesX","deltaX","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","meshData","totalNodes","colIndex","basisFunctions","gaussPointsAndWeights","localToGlobalMap","numNodes","performIsoparametricMapping1D","params","xCoordinates","ksiDerivX","localNodeIndex","detJacobian","basisFunctionDerivX","performIsoparametricMapping2D","yCoordinates","etaDerivX","ksiDerivY","etaDerivY","basisFunctionDerivY","ThermalBoundaryConditions","boundaryConditions","imposeConstantTempBoundaryConditions","Object","keys","boundaryKey","tempValue","globalNodeIndex","imposeConstantTempBoundaryConditionsFront","nodeConstraintCode","boundaryValues","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","basisFunctionsAndDerivatives","tangentVectorLength","localNodeIndex2","globalNodeIndex2","gaussPointIndex","imposeConvectionBoundaryConditionsFront","localJacobianMatrix","map","localResidualVector","boundaryElement","find","_","assembleHeatConductionFront","FEAData","ngl","gaussPointIndex1","localNodeIndex1","gaussPointIndex2","globalIndex","GenericBoundaryConditions","imposeDirichletBoundaryConditions","value","imposeConstantValueBoundaryConditionsFront","assembleFrontPropagationMat","eikonalActivationFlag","eikonalViscousTerm","totalElements","mappingResult","solutionDerivX","solutionDerivY","localToGlobalMap1","localToGlobalMap2","assembleFrontPropagationFront","frontalData","frontalState","elementData","currentElementIndex","frontStorage","runFrontalSolver","assembleFront","numElements","globalResidualVector","topologyData","lateralData","writeFlag","transformationFlag","nodesPerElement","determinant","systemSize","globalSolutionVector","frontDataIndex","frontSize","frontWidthEstimate","ceil","estimateFrontSize","frontValues","columnHeaders","pivotRow","pivotData","initializeFrontalArrays","dirichletBoundaryConditionsHandler","currentSolutionVector","thermalBoundaryConditions","pivotColumnGlobalIndex","localDestination","rowDestination","rowHeaders","pivotRowIndices","pivotColumnIndices","modifiedRows","pivotColumn","frontMatrix","rowSwapCount","columnSwapCount","lastAppearanceCheck","frontDataCounter","pivotDataIndex","summedRows","reverseElementIndex","columnCount","rowCount","assembled","numElementNodes","numElementColumns","assembleElementContribution","currentElement","columnIndex","rowIndex","localColumnIndex","frontColumnIndex","localRowIndex","availableColumnCount","constrainedRowCount","availableRowCount","absoluteNodeIndex","constrainedIndex","pivotRowIndex","pivotColumnIndex","pivotValue","testColumnIndex","testRowIndex","testValue","pivotGlobalRowIndex","permutationHelper","rightHandSide","globalRowIndex","eliminationFactor","performBackSubstitution","runFrontalAlgorithm","toExponential","finalNodesX","finalNodesY","slice","nodesCoordinates","boundaryLocalJacobianMatrix","boundaryResidualVector","isOnRobinTypeBoundary","some","result","localNodeI","localNodeJ","iterationIndex","accumulatedValue","newtonRaphson","assembleMat","context","errorNorm","initialSolution","Number","FEAScriptModel","solverConfig","meshConfig","coefficientFunctions","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","error","Error","mesh","nodesCoordinatesAndNumbering","prepareMesh","assembleHeatConductionMat","eikonalExteralIterations","newtonRaphsonResult","A","B","C","D","xCoord","a","b","d","globalNodeIndex1","assembleGeneralFormPDEMat","importGmshQuadTri","async","file","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","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","l","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","printVersion"],"mappings":"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"} \ No newline at end of file diff --git a/dist/feascript.umd.js b/dist/feascript.umd.js index 1a91025..4427bdd 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 w=Symbol("Comlink.proxy"),O=Symbol("Comlink.endpoint"),S=Symbol("Comlink.releaseProxy"),X=Symbol("Comlink.finalizer"),V=Symbol("Comlink.thrown"),T=e=>"object"==typeof e&&null!==e||"function"==typeof e,k=new Map([["proxy",{canHandle:e=>T(e)&&e[w],serialize(e){const{port1:t,port2:n}=new MessageChannel;return P(e,t),[n,[n]]},deserialize:e=>(e.start(),Y(e))}],["throw",{canHandle:e=>T(e)&&V 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(H);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]]=H(s.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[w]:!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,[V]:0}}Promise.resolve(d).catch((e=>({value:e,[V]: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),X in e&&"function"==typeof e[X]&&e[X]())})).catch((e=>{const[n,o]=J({value:new TypeError("Unserializable return value"),[V]: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 Y(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)}})),W(e,n,[],t)}function I(e){if(e)throw new Error("Proxy has been released and is not useable")}function B(e){return L(e,new Map,{type:"RELEASE"}).then((()=>{R(e)}))}const q=new WeakMap,j="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(q.get(e)||0)-1;q.set(e,t),0===t&&B(e)}));function W(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(I(s),r===S)return()=>{!function(e){j&&j.unregister(e)}(i),B(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=L(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(H);return o.then.bind(o)}return W(e,t,[...n,r])},set(o,i,r){I(s);const[a,l]=J(r);return L(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(H)},apply(o,i,r){I(s);const a=n[n.length-1];if(a===O)return L(e,t,{type:"ENDPOINT"}).then(H);if("bind"===a)return W(e,t,n.slice(0,-1));const[l,d]=G(r);return L(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(H)},construct(o,i){I(s);const[r,a]=G(i);return L(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(H)}});return function(e,t){const n=(q.get(t)||0)+1;q.set(t,n),j&&j.register(e,t,e)}(i,e),i}function G(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 k)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 H(e){switch(e.type){case"HANDLER":return k.get(e.name).deserialize(e.value);case"RAW":return e.value}}function L(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",this.coefficientFunctions=null,s("FEAScriptModel instance created")}setSolverConfig(e,t={}){this.solverConfig=e,t&&t.coefficientFunctions&&(this.coefficientFunctions=t.coefficientFunctions,o("Coefficient functions set")),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=[],a=[];s("Preparing mesh...");const l=function(e){const{meshDimension:t,numElementsX:n,numElementsY:s,maxX:r,maxY:a,elementOrder:l,parsedMesh:c}=e;let m;"1D"===t?m=new d({numElementsX:n,maxX:r,elementOrder:l,parsedMesh:c}):"2D"===t?m=new u({numElementsX:n,maxX:r,numElementsY:s,maxY:a,elementOrder:l,parsedMesh:c}):i("Mesh dimension must be either '1D' or '2D'.");const h=m.boundaryElementsProcessed?m.parsedMesh:m.generateMesh();let f,p,b=h.nodesXCoordinates,y=h.nodesYCoordinates,g=h.totalNodesX,E=h.totalNodesY,v=h.nodalNumbering,M=h.boundaryElements;return null!=c?(f=v.length,p=b.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:b,nodesYCoordinates:y,totalNodesX:g,totalNodesY:E,nop:v,boundaryElements:M,totalElements:f,totalNodes:p,meshDimension:t,elementOrder:l}}(this.meshConfig);s("Mesh preparation completed");const c={nodesXCoordinates:l.nodesXCoordinates,nodesYCoordinates:l.nodesYCoordinates};if(s("Beginning solving process..."),console.time("totalSolvingTime"),"heatConductionScript"===this.solverConfig)if(s(`Using solver: ${this.solverConfig}`),"frontal"===this.solverMethod){n=F(b,l,this.boundaryConditions).solutionVector}else{({jacobianMatrix:e,residualVector:t}=function(e,t){s("Starting solid heat transfer matrix assembly...");const{nodesXCoordinates:n,nodesYCoordinates:o,nop:i,boundaryElements:r,totalElements:a,meshDimension:l,elementOrder:d}=e,u=m(e),{residualVector:c,jacobianMatrix:b,localToGlobalMap:y,basisFunctions:g,gaussPoints:E,gaussWeights:v,numNodes:M}=u;for(let e=0;e0&&(r.initialSolution=[...n]);const s=N(g,r,100,1e-4);e=s.jacobianMatrix,t=s.residualVector,n=s.solutionVector,o+=1/i}}else if("generalFormPDEScript"===this.solverConfig)if(s(`Using solver: ${this.solverConfig}`),"frontal"===this.solverMethod)i("Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.");else{({jacobianMatrix:e,residualVector:t}=function(e,t,n){s("Starting general form PDE matrix assembly...");const{nodesXCoordinates:o,nodesYCoordinates:r,nop:a,boundaryElements:l,totalElements:d,meshDimension:u,elementOrder:c}=e,{A:f,B:p,C:b,D:g}=n,E=m(e),{residualVector:v,jacobianMatrix:M,localToGlobalMap:C,basisFunctions:D,gaussPoints:$,gaussWeights:F,numNodes:A}=E;if("1D"===u)for(let e=0;e{console.error("FEAScriptWorker: Worker error:",e)};const e=Y(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.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},u=0,c=[],m=0,h=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},b=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);b++,b===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,u={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],u,{responsive:!0})}else if("2D"===o&&"contour"===s){const t="structured"===r,o=new Set(a).size,d=new Set(l).size;let u;u=Array.isArray(e[0])?e.map((e=>e[0])):e;let c=Math.min(window.innerWidth,700),m=Math.max(...a),h=Math.max(...l)/m,f=Math.min(c,600),p={title:`${s} plot - ${n}`,width:f,height:f*h*.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]),u=math.transpose(r),c=[];for(let e=0;e"object"==typeof e&&null!==e||"function"==typeof e,k=new Map([["proxy",{canHandle:e=>T(e)&&e[w],serialize(e){const{port1:t,port2:n}=new MessageChannel;return P(e,t),[n,[n]]},deserialize:e=>(e.start(),Y(e))}],["throw",{canHandle:e=>T(e)&&V 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(H);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]]=H(s.data.value),d=!0;break;case"APPLY":d=n.apply(t,l);break;case"CONSTRUCT":d=function(e){return Object.assign(e,{[w]:!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,[V]:0}}Promise.resolve(d).catch((e=>({value:e,[V]: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),X in e&&"function"==typeof e[X]&&e[X]())})).catch((e=>{const[n,o]=J({value:new TypeError("Unserializable return value"),[V]: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 Y(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)}})),W(e,n,[],t)}function I(e){if(e)throw new Error("Proxy has been released and is not useable")}function B(e){return L(e,new Map,{type:"RELEASE"}).then((()=>{R(e)}))}const q=new WeakMap,j="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(q.get(e)||0)-1;q.set(e,t),0===t&&B(e)}));function W(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(I(s),r===S)return()=>{!function(e){j&&j.unregister(e)}(i),B(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=L(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(H);return o.then.bind(o)}return W(e,t,[...n,r])},set(o,i,r){I(s);const[a,l]=J(r);return L(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(H)},apply(o,i,r){I(s);const a=n[n.length-1];if(a===O)return L(e,t,{type:"ENDPOINT"}).then(H);if("bind"===a)return W(e,t,n.slice(0,-1));const[l,d]=G(r);return L(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:l},d).then(H)},construct(o,i){I(s);const[r,a]=G(i);return L(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(H)}});return function(e,t){const n=(q.get(t)||0)+1;q.set(t,n),j&&j.register(e,t,e)}(i,e),i}function G(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 k)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 H(e){switch(e.type){case"HANDLER":return k.get(e.name).deserialize(e.value);case"RAW":return e.value}}function L(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",this.coefficientFunctions=null,s("FEAScriptModel instance created")}setSolverConfig(e,t={}){this.solverConfig=e,t&&t.coefficientFunctions&&(this.coefficientFunctions=t.coefficientFunctions,o("Coefficient functions set")),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=[],a=[];s("Preparing mesh...");const l=function(e){const{meshDimension:t,numElementsX:n,numElementsY:s,maxX:r,maxY:a,elementOrder:l,parsedMesh:c}=e;let m;"1D"===t?m=new d({numElementsX:n,maxX:r,elementOrder:l,parsedMesh:c}):"2D"===t?m=new u({numElementsX:n,maxX:r,numElementsY:s,maxY:a,elementOrder:l,parsedMesh:c}):i("Mesh dimension must be either '1D' or '2D'.");const h=m.boundaryElementsProcessed?m.parsedMesh:m.generateMesh();let f,p,b=h.nodesXCoordinates,y=h.nodesYCoordinates,g=h.totalNodesX,E=h.totalNodesY,v=h.nodalNumbering,M=h.boundaryElements;return null!=c?(f=v.length,p=b.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:b,nodesYCoordinates:y,totalNodesX:g,totalNodesY:E,nop:v,boundaryElements:M,totalElements:f,totalNodes:p,meshDimension:t,elementOrder:l}}(this.meshConfig);s("Mesh preparation completed");const c={nodesXCoordinates:l.nodesXCoordinates,nodesYCoordinates:l.nodesYCoordinates};if(s("Beginning solving process..."),console.time("totalSolvingTime"),"heatConductionScript"===this.solverConfig)if(s(`Using solver: ${this.solverConfig}`),"frontal"===this.solverMethod){n=F(b,l,this.boundaryConditions).solutionVector}else{({jacobianMatrix:e,residualVector:t}=function(e,t){s("Starting solid heat transfer matrix assembly...");const{nodesXCoordinates:n,nodesYCoordinates:o,nop:i,boundaryElements:r,totalElements:a,meshDimension:l,elementOrder:d}=e,u=m(e),{residualVector:c,jacobianMatrix:b,localToGlobalMap:y,basisFunctions:g,gaussPoints:E,gaussWeights:v,numNodes:M}=u;for(let e=0;e0&&(r.initialSolution=[...n]);const s=N(g,r,100,1e-4);e=s.jacobianMatrix,t=s.residualVector,n=s.solutionVector,o+=1/i}}else if("generalFormPDEScript"===this.solverConfig)if(s(`Using solver: ${this.solverConfig}`),"frontal"===this.solverMethod)i("Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.");else{({jacobianMatrix:e,residualVector:t}=function(e,t,n){s("Starting general form PDE matrix assembly...");const{nodesXCoordinates:o,nodesYCoordinates:r,nop:a,boundaryElements:l,totalElements:d,meshDimension:u,elementOrder:c}=e,{A:f,B:p,C:b,D:g}=n,E=m(e),{residualVector:v,jacobianMatrix:M,localToGlobalMap:C,basisFunctions:D,gaussPoints:$,gaussWeights:F,numNodes:A}=E;if("1D"===u)for(let e=0;e{console.error("FEAScriptWorker: Worker error:",e)};const e=Y(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.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},u=0,c=[],m=0,h=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},b=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);b++,b===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,u={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],u,{responsive:!0})}else if("2D"===o&&"contour"===s){const t="structured"===r,o=new Set(a).size,d=new Set(l).size;let u;u=Array.isArray(e[0])?e.map((e=>e[0])):e;let c=Math.min(window.innerWidth,700),m=Math.max(...a),h=Math.max(...l)/m,f=Math.min(c,600),p={title:`${s} plot - ${n}`,width:f,height:f*h*.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]),u=math.transpose(r),c=[];for(let e=0;e | |\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 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/**\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 * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\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 constant temperature boundary conditions for the frontal solver\n * @param {array} nodeConstraintCode - Array indicating boundary condition code for each node\n * @param {array} boundaryValues - Array containing boundary condition values\n */\n imposeConstantTempBoundaryConditionsFront(nodeConstraintCode, boundaryValues) {\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\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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 // 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 * Function to impose convection boundary conditions for the frontal solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @returns {object} An object containing:\n * - localJacobianMatrix: Local Jacobian matrix with convection contributions\n * - localResidualVector: Residual vector with convection contributions\n */\n imposeConvectionBoundaryConditionsFront(\n elementIndex,\n nodesXCoordinates,\n nodesYCoordinates,\n gaussPoints,\n gaussWeights,\n basisFunctions\n ) {\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 // Initialize local Jacobian matrix and local residual vector\n const numNodes = this.nop[elementIndex].length;\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Check if this element is on a convection boundary\n for (const boundaryKey in this.boundaryElements) {\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\n // Find if this element is on this boundary and which side\n const boundaryElement = this.boundaryElements[boundaryKey].find(\n ([elemIdx, _]) => elemIdx === elementIndex\n );\n\n if (boundaryElement) {\n const side = boundaryElement[1];\n\n if (this.meshDimension === \"1D\") {\n // Handle 1D case\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n nodeIndex = side === 0 ? 0 : 1;\n } else if (this.elementOrder === \"quadratic\") {\n nodeIndex = side === 0 ? 0 : 2;\n }\n\n // Add contribution to local Jacobian matrix and local residual vector\n debugLog(\n ` - Applied convection boundary condition to node ${nodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n localResidualVector[nodeIndex] += -convectionCoeff * extTemp;\n localJacobianMatrix[nodeIndex][nodeIndex] += convectionCoeff;\n } else if (this.meshDimension === \"2D\") {\n // Handle 2D case\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n\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 // Get basis functions\n const basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n const basisFunction = basisFunctionsAndDerivatives.basisFunction;\n const basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n const basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n // Calculate tangent vector components\n let ksiDerivX = 0,\n ksiDerivY = 0,\n etaDerivX = 0,\n etaDerivY = 0;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n } else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute tangent vector length\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 // Apply boundary conditions to local matrices\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n localResidualVector[localNodeIndex] +=\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 localJacobianMatrix[localNodeIndex][localNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n // Handle quadratic elements (similar pattern but with more Gauss points)\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n\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 // Apply boundary conditions to local matrices\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n localResidualVector[localNodeIndex] +=\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 localJacobianMatrix[localNodeIndex][localNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n }\n }\n }\n }\n\n return { localJacobianMatrix, localResidualVector };\n }\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 *\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\nexport function assembleHeatConductionMat(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 const 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 const 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 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\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\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 residual vector for the solid heat transfer model when using the frontal system solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nop - Nodal connectivity array (element-to-node mapping)\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @param {object} FEAData - Object containing FEA-related data\n * @returns {object} An object containing:\n * - localJacobianMatrix: Local Jacobian matrix\n * - localResidualVector: Residual vector contributions\n * - ngl: Array mapping local node indices to global node indices\n */\nexport function assembleHeatConductionFront({ elementIndex, nop, meshData, basisFunctions, FEAData }) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n // Loop over Gauss points\n if (meshDimension === \"1D\") {\n // 1D solid heat transfer\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n // 2D solid heat transfer\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } =\n basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1], gaussPoints[gaussPointIndex2]);\n\n // Create mapping from local element space to global mesh (convert to 0-based indexing)\n const localToGlobalMap = ngl.map((globalIndex) => globalIndex - 1);\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\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 return { localJacobianMatrix, localResidualVector, ngl };\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 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 Dirichlet boundary conditions\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n *\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\n imposeDirichletBoundaryConditions(residualVector, jacobianMatrix) {\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 value\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 value\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 value\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 value\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 * Function to impose constant value (Dirichlet) boundary conditions for the frontal solver\n * @param {array} nodeConstraintCode - Array indicating boundary condition code for each node\n * @param {array} boundaryValues - Array containing boundary condition values\n */\n imposeConstantValueBoundaryConditionsFront(nodeConstraintCode, boundaryValues) {\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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// Base viscous term that remains when eikonal equation is fully activated\nconst baseEikonalViscousTerm = 1e-2;\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 let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n debugLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n debugLog(`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 // Unsupported 1D front propagation\n errorLog(\"1D front propagation is not yet supported\");\n\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 // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // TODO 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 eikonalActivationFlag *\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 const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Dirichlet boundary conditions\n genericBoundaryConditions.imposeDirichletBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n\n/**\n * Function to assemble the local Jacobian matrix and residual vector for the front propagation model when using the frontal system solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nop - Nodal connectivity array (element-to-node mapping)\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @param {object} FEAData - Object containing FEA-related data\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 * - localJacobianMatrix: Local Jacobian matrix\n * - residualVector: Residual vector contributions\n * - ngl: Array mapping local node indices to global node indices\n */\nexport function assembleFrontPropagationFront({\n elementIndex,\n nop,\n meshData,\n basisFunctions,\n FEAData,\n solutionVector,\n eikonalActivationFlag,\n}) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n\n // Calculate eikonal viscous term\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(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 // Unsupported 1D front propagation\n errorLog(\"1D front propagation is not yet supported\");\n\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 // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // localJacobianMatrix\n // TODO localJacobianMatrix 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 // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } =\n basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1], gaussPoints[gaussPointIndex2]);\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\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 // Viscous term contribution\n localResidualVector[localNodeIndex1] +=\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 // Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n localResidualVector[localNodeIndex1] +=\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 // Viscous term contribution\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n\n // Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] +=\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 eikonalActivationFlag *\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 return { localJacobianMatrix, localResidualVector, ngl };\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 { initializeFEA } from \"../mesh/meshUtilsScript.js\";\nimport { assembleHeatConductionFront } from \"../solvers/heatConductionScript.js\";\nimport { ThermalBoundaryConditions } from \"../solvers/thermalBoundaryConditionsScript.js\";\nimport { assembleFrontPropagationFront } from \"../solvers/frontPropagationScript.js\";\nimport { GenericBoundaryConditions } from \"../solvers/genericBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// Create object templates\nconst frontalData = {};\nconst frontalState = {};\nconst elementData = { currentElementIndex: 0 };\nconst frontStorage = {};\nlet basisFunctions;\n\n/**\n * Function to run the frontal solver and obtain results for plotting\n * @param {function} assembleFront - Matrix assembler based on the physical model\n * @param {object} meshData - Object containing mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions\n * @param {object} [options] - Additional options for the solver\n * @returns {object} An object containing the solution vector and node coordinates\n */\nexport function runFrontalSolver(assembleFront, meshData, boundaryConditions, options = {}) {\n // Initialize FEA components\n const FEAData = initializeFEA(meshData);\n const totalNodes = meshData.nodesXCoordinates.length;\n const numElements = meshData.totalElements;\n const numNodes = FEAData.numNodes;\n\n // Calculate required array sizes\n initializeFrontalArrays(numNodes, numElements);\n\n // Start timing for system solving (frontal algorithm)\n basicLog(\"Solving system using frontal...\");\n console.time(\"systemSolving\");\n\n // Initialize basis functions\n basisFunctions = new BasisFunctions({\n meshDimension: meshData.meshDimension,\n elementOrder: meshData.elementOrder,\n });\n\n // Copy node connectivity array into frontalData storage\n for (let elementIndex = 0; elementIndex < meshData.totalElements; elementIndex++) {\n for (let nodeIndex = 0; nodeIndex < FEAData.numNodes; nodeIndex++) {\n frontalData.nodalNumbering[elementIndex][nodeIndex] = meshData.nop[elementIndex][nodeIndex];\n }\n }\n\n // Apply Dirichlet-type boundary conditions\n // Initialize all nodes with no boundary condition\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.nodeConstraintCode[nodeIndex] = 0;\n frontalData.boundaryValues[nodeIndex] = 0;\n }\n\n // Handle Dirichlet-type boundary conditions differently based on which solver is being used\n let dirichletBoundaryConditionsHandler;\n // Solid heat transfer model (heatConductionScript solver)\n if (assembleFront === assembleHeatConductionFront) {\n dirichletBoundaryConditionsHandler = new ThermalBoundaryConditions(\n boundaryConditions,\n meshData.boundaryElements,\n meshData.nop,\n meshData.meshDimension,\n meshData.elementOrder\n );\n\n dirichletBoundaryConditionsHandler.imposeConstantTempBoundaryConditionsFront(\n frontalData.nodeConstraintCode,\n frontalData.boundaryValues\n );\n // Front propagation model (frontPropagationScript solver)\n } else if (assembleFront === assembleFrontPropagationFront) {\n dirichletBoundaryConditionsHandler = new GenericBoundaryConditions(\n boundaryConditions,\n meshData.boundaryElements,\n meshData.nop,\n meshData.meshDimension,\n meshData.elementOrder\n );\n\n dirichletBoundaryConditionsHandler.imposeConstantValueBoundaryConditionsFront(\n frontalData.nodeConstraintCode,\n frontalData.boundaryValues\n );\n }\n // Initialize global residual vector\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.globalResidualVector[nodeIndex] = 0;\n }\n\n frontalState.totalNodes = meshData.nodesXCoordinates.length;\n frontalState.writeFlag = 0;\n frontalState.transformationFlag = 1;\n frontalState.determinant = 1;\n\n for (let elementIndex = 0; elementIndex < meshData.totalElements; elementIndex++) {\n frontalState.nodesPerElement[elementIndex] = FEAData.numNodes;\n }\n\n // Parameters for non-linear assemblers\n frontalState.currentSolutionVector = options.solutionVector;\n frontalState.eikonalActivationFlag = options.eikonalActivationFlag;\n\n // Pass assembleFront and dirichletBoundaryConditionsHandler to runFrontalAlgorithm\n runFrontalAlgorithm(meshData, FEAData, dirichletBoundaryConditionsHandler, assembleFront);\n\n // Copy solution\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.solutionVector[nodeIndex] = frontalState.globalSolutionVector[nodeIndex];\n }\n\n // Output results to console for debugging\n const { nodesXCoordinates, nodesYCoordinates } = meshData;\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n if (meshData.meshDimension === \"1D\") {\n // 1D case - only output X coordinates and temperature\n debugLog(\n `${nodesXCoordinates[nodeIndex].toExponential(5)} ${frontalData.solutionVector[\n nodeIndex\n ].toExponential(5)}`\n );\n } else {\n // 2D case - output X, Y coordinates and temperature\n debugLog(\n `${nodesXCoordinates[nodeIndex].toExponential(5)} ${nodesYCoordinates[nodeIndex].toExponential(\n 5\n )} ${frontalData.solutionVector[nodeIndex].toExponential(5)}`\n );\n }\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n const { nodesXCoordinates: finalNodesX, nodesYCoordinates: finalNodesY } = meshData;\n return {\n solutionVector: frontalData.solutionVector.slice(0, totalNodes),\n nodesCoordinates: {\n nodesXCoordinates: finalNodesX,\n nodesYCoordinates: finalNodesY,\n },\n };\n}\n\n/**\n * Function to initialize arrays dynamically based on problem size\n * @param {number} numNodes - Number of nodes per element\n * @param {number} numElements - Number of elements in the mesh\n */\nfunction initializeFrontalArrays(numNodes, numElements) {\n // Use the actual number of elements from the mesh\n frontalData.nodalNumbering = Array(numElements)\n .fill()\n .map(() => Array(numNodes).fill(0));\n frontalData.nodeConstraintCode = Array(numNodes).fill(0);\n frontalData.boundaryValues = Array(numNodes).fill(0);\n frontalData.globalResidualVector = Array(numNodes).fill(0);\n frontalData.solutionVector = Array(numNodes).fill(0);\n frontalData.topologyData = Array(numElements).fill(0);\n frontalData.lateralData = Array(numElements).fill(0);\n\n // Initialize frontalState arrays\n frontalState.writeFlag = 0;\n frontalState.totalNodes = numNodes;\n frontalState.transformationFlag = 0;\n frontalState.nodesPerElement = Array(numElements).fill(0);\n frontalState.determinant = 1;\n\n // For matrix operations, estimate required size based on problem complexity\n const systemSize = Math.max(numNodes, 2000);\n frontalState.globalSolutionVector = Array(systemSize).fill(0);\n frontalState.frontDataIndex = 0;\n\n // Initialize elementData arrays\n elementData.localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n elementData.currentElementIndex = 0;\n\n // Initialize frontStorage arrays\n const frontSize = estimateFrontSize(numNodes, numElements);\n frontStorage.frontValues = Array(frontSize).fill(0);\n frontStorage.columnHeaders = Array(systemSize).fill(0);\n frontStorage.pivotRow = Array(systemSize).fill(0);\n frontStorage.pivotData = Array(frontSize).fill(0);\n}\n\n/**\n * Function to estimate the required front size\n * @param {number} numNodes - Number of of nodes per element\n * @param {number} numElements - Number of elements in the mesh\n * @returns {number} Estimated front size\n */\nfunction estimateFrontSize(numNodes, numElements) {\n const frontWidthEstimate = Math.max(Math.ceil(Math.sqrt(numElements)) * numNodes, numNodes * 2);\n return frontWidthEstimate * numElements;\n}\n// Old function to estimate the required front size\n// function estimateFrontSize(numNodes, numElements, numNodes) {\n// const frontWidthEstimate = Math.ceil(Math.sqrt(numElements) * numNodes * 2);\n// const frontSize = frontWidthEstimate * numNodes * 4;\n// return Math.max(frontSize, 10000);\n// }\n\n/**\n * Function to compute local Jacobian matrix and local residual vector\n * @param {object} meshData - Object containing mesh data\n * @param {object} FEAData - Object containing FEA-related data\n * @param {object} thermalBoundaryConditions - Object containing thermal boundary conditions\n * @param {function} assembleFront - Matrix assembler based on the physical model\n */\nfunction assembleElementContribution(meshData, FEAData, thermalBoundaryConditions, assembleFront) {\n const elementIndex = elementData.currentElementIndex - 1;\n\n // Guard against out-of-range indices\n if (elementIndex < 0 || elementIndex >= meshData.totalElements) {\n errorLog(`Skipping out-of-range elementIndex=${elementIndex} (totalElements=${meshData.totalElements})`);\n return false;\n }\n\n // Domain terms\n const { localJacobianMatrix, localResidualVector, ngl } = assembleFront({\n elementIndex,\n nop: frontalData.nodalNumbering,\n meshData,\n basisFunctions: basisFunctions,\n FEAData,\n // These are ignored by linear assemblers\n solutionVector: frontalState.currentSolutionVector,\n eikonalActivationFlag: frontalState.eikonalActivationFlag,\n });\n\n // Handle Robin-type boundary conditions differently based on which solver is being used\n let boundaryLocalJacobianMatrix = Array(FEAData.numNodes)\n .fill()\n .map(() => Array(FEAData.numNodes).fill(0));\n let boundaryResidualVector = Array(FEAData.numNodes).fill(0);\n\n // heatConductionScript solver\n if (assembleFront === assembleHeatConductionFront) {\n // Check if this element is on a Robin-type boundary\n let isOnRobinTypeBoundary = false;\n for (const boundaryKey in meshData.boundaryElements) {\n if (\n thermalBoundaryConditions.boundaryConditions[boundaryKey]?.[0] === \"convection\" &&\n meshData.boundaryElements[boundaryKey].some(([elemIdx, _]) => elemIdx === elementIndex)\n ) {\n isOnRobinTypeBoundary = true;\n break;\n }\n }\n\n // Only calculate Robin-type for elements when required\n if (isOnRobinTypeBoundary) {\n const { gaussPoints, gaussWeights } = FEAData;\n const result = thermalBoundaryConditions.imposeConvectionBoundaryConditionsFront(\n elementIndex,\n meshData.nodesXCoordinates,\n meshData.nodesYCoordinates,\n gaussPoints,\n gaussWeights,\n basisFunctions\n );\n boundaryLocalJacobianMatrix = result.localJacobianMatrix;\n boundaryResidualVector = result.localResidualVector;\n }\n } else if (assembleFront === assembleFrontPropagationFront) {\n // For now, no Robin-type boundary conditions exist for any other solver\n }\n\n // Combine domain and boundary contributions\n for (let localNodeI = 0; localNodeI < FEAData.numNodes; localNodeI++) {\n for (let localNodeJ = 0; localNodeJ < FEAData.numNodes; localNodeJ++) {\n elementData.localJacobianMatrix[localNodeI][localNodeJ] =\n localJacobianMatrix[localNodeI][localNodeJ] + boundaryLocalJacobianMatrix[localNodeI][localNodeJ];\n }\n }\n\n // Assemble local element residual\n for (let localNodeIndex = 0; localNodeIndex < FEAData.numNodes; localNodeIndex++) {\n const globalNodeIndex = ngl[localNodeIndex] - 1;\n frontalData.globalResidualVector[globalNodeIndex] +=\n localResidualVector[localNodeIndex] + boundaryResidualVector[localNodeIndex];\n }\n\n return true;\n}\n\n/**\n * Function to implement the frontal solver algorithm\n * @param {object} meshData - Object containing mesh data\n * @param {object} FEAData - Object containing FEA-related data\n * @param {object} thermalBoundaryConditions - Object containing thermal boundary conditions\n * @param {function} assembleFront - Matrix assembler based on the physical model\n */\nfunction runFrontalAlgorithm(meshData, FEAData, thermalBoundaryConditions, assembleFront) {\n // Allocate local arrays dynamically\n const totalElements = meshData.totalElements;\n const numNodes = meshData.nodesXCoordinates.length;\n const systemSize = Math.max(numNodes, frontalState.globalSolutionVector.length);\n let localDestination = Array(FEAData.numNodes).fill(0);\n let rowDestination = Array(FEAData.numNodes).fill(0);\n let rowHeaders = Array(systemSize).fill(0);\n let pivotRowIndices = Array(systemSize).fill(0);\n let pivotColumnIndices = Array(systemSize).fill(0);\n let modifiedRows = Array(systemSize).fill(0);\n let pivotColumn = Array(systemSize).fill(0);\n let frontMatrix = Array(systemSize)\n .fill()\n .map(() => Array(systemSize).fill(0));\n let rowSwapCount = Array(numNodes).fill(0);\n let columnSwapCount = Array(numNodes).fill(0);\n let lastAppearanceCheck = Array(numNodes).fill(0);\n let pivotColumnGlobalIndex; // Pivot column global index\n\n let frontDataCounter = 1;\n frontalState.writeFlag++;\n let pivotDataIndex = 1;\n let summedRows = 1;\n elementData.currentElementIndex = 0;\n\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n rowSwapCount[nodeIndex] = 0;\n columnSwapCount[nodeIndex] = 0;\n }\n\n if (frontalState.transformationFlag !== 0) {\n // Prefront: find last appearance of each node\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n lastAppearanceCheck[nodeIndex] = 0;\n }\n\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n let reverseElementIndex = totalElements - elementIndex - 1;\n for (\n let localNodeIndex = 0;\n localNodeIndex < frontalState.nodesPerElement[reverseElementIndex];\n localNodeIndex++\n ) {\n let globalNodeIndex = frontalData.nodalNumbering[reverseElementIndex][localNodeIndex];\n if (lastAppearanceCheck[globalNodeIndex - 1] === 0) {\n lastAppearanceCheck[globalNodeIndex - 1] = 1;\n frontalData.nodalNumbering[reverseElementIndex][localNodeIndex] =\n -frontalData.nodalNumbering[reverseElementIndex][localNodeIndex];\n }\n }\n }\n }\n\n frontalState.transformationFlag = 0;\n let columnCount = 0;\n let rowCount = 0;\n\n for (let i = 0; i < systemSize; i++) {\n for (let j = 0; j < systemSize; j++) {\n frontMatrix[j][i] = 0;\n }\n }\n\n while (true) {\n // Assemble a new element only while we still have elements\n let assembled = false;\n let numElementNodes = 0;\n let numElementColumns = 0;\n\n if (elementData.currentElementIndex < totalElements) {\n elementData.currentElementIndex++;\n assembled = assembleElementContribution(meshData, FEAData, thermalBoundaryConditions, assembleFront);\n }\n\n if (assembled) {\n const currentElement = elementData.currentElementIndex;\n numElementNodes = frontalState.nodesPerElement[currentElement - 1];\n numElementColumns = frontalState.nodesPerElement[currentElement - 1];\n\n for (let localNodeIndex = 0; localNodeIndex < numElementColumns; localNodeIndex++) {\n let globalNodeIndex = frontalData.nodalNumbering[currentElement - 1][localNodeIndex];\n let columnIndex;\n\n if (columnCount === 0) {\n columnCount++;\n localDestination[localNodeIndex] = columnCount;\n frontStorage.columnHeaders[columnCount - 1] = globalNodeIndex;\n } else {\n for (columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n if (Math.abs(globalNodeIndex) === Math.abs(frontStorage.columnHeaders[columnIndex])) break;\n }\n\n if (columnIndex === columnCount) {\n columnCount++;\n localDestination[localNodeIndex] = columnCount;\n frontStorage.columnHeaders[columnCount - 1] = globalNodeIndex;\n } else {\n localDestination[localNodeIndex] = columnIndex + 1;\n frontStorage.columnHeaders[columnIndex] = globalNodeIndex;\n }\n }\n\n let rowIndex;\n if (rowCount === 0) {\n rowCount++;\n rowDestination[localNodeIndex] = rowCount;\n rowHeaders[rowCount - 1] = globalNodeIndex;\n } else {\n for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n if (Math.abs(globalNodeIndex) === Math.abs(rowHeaders[rowIndex])) break;\n }\n\n if (rowIndex === rowCount) {\n rowCount++;\n rowDestination[localNodeIndex] = rowCount;\n rowHeaders[rowCount - 1] = globalNodeIndex;\n } else {\n rowDestination[localNodeIndex] = rowIndex + 1;\n rowHeaders[rowIndex] = globalNodeIndex;\n }\n }\n }\n\n if (rowCount > systemSize || columnCount > systemSize) {\n errorLog(\"Error: systemSize not large enough\");\n return;\n }\n\n for (let localColumnIndex = 0; localColumnIndex < numElementColumns; localColumnIndex++) {\n let frontColumnIndex = localDestination[localColumnIndex];\n for (let localRowIndex = 0; localRowIndex < numElementNodes; localRowIndex++) {\n let frontRowIndex = rowDestination[localRowIndex];\n frontMatrix[frontRowIndex - 1][frontColumnIndex - 1] +=\n elementData.localJacobianMatrix[localRowIndex][localColumnIndex];\n }\n }\n }\n\n // Pivoting/elimination continues whether or not a new element was assembled\n let availableColumnCount = 0;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n if (frontStorage.columnHeaders[columnIndex] < 0) {\n pivotColumnIndices[availableColumnCount] = columnIndex + 1;\n availableColumnCount++;\n }\n }\n\n let constrainedRowCount = 0;\n let availableRowCount = 0;\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n let globalNodeIndex = rowHeaders[rowIndex];\n if (globalNodeIndex < 0) {\n pivotRowIndices[availableRowCount] = rowIndex + 1;\n availableRowCount++;\n let absoluteNodeIndex = Math.abs(globalNodeIndex);\n if (frontalData.nodeConstraintCode[absoluteNodeIndex - 1] === 1) {\n modifiedRows[constrainedRowCount] = rowIndex + 1;\n constrainedRowCount++;\n frontalData.nodeConstraintCode[absoluteNodeIndex - 1] = 2;\n frontalData.globalResidualVector[absoluteNodeIndex - 1] =\n frontalData.boundaryValues[absoluteNodeIndex - 1];\n }\n }\n }\n\n if (constrainedRowCount > 0) {\n for (let constrainedIndex = 0; constrainedIndex < constrainedRowCount; constrainedIndex++) {\n let rowIndex = modifiedRows[constrainedIndex] - 1;\n let globalNodeIndex = Math.abs(rowHeaders[rowIndex]);\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex][columnIndex] = 0;\n let columnGlobalIndex = Math.abs(frontStorage.columnHeaders[columnIndex]);\n if (columnGlobalIndex === globalNodeIndex) frontMatrix[rowIndex][columnIndex] = 1;\n }\n }\n }\n\n if (availableColumnCount > summedRows || elementData.currentElementIndex < totalElements) {\n if (availableColumnCount === 0) {\n errorLog(\"Error: no more rows fully summed\");\n return;\n }\n\n let pivotRowIndex = pivotRowIndices[0];\n let pivotColumnIndex = pivotColumnIndices[0];\n let pivotValue = frontMatrix[pivotRowIndex - 1][pivotColumnIndex - 1];\n\n if (Math.abs(pivotValue) < 1e-4) {\n pivotValue = 0;\n for (let columnIndex = 0; columnIndex < availableColumnCount; columnIndex++) {\n let testColumnIndex = pivotColumnIndices[columnIndex];\n for (let rowIndex = 0; rowIndex < availableRowCount; rowIndex++) {\n let testRowIndex = pivotRowIndices[rowIndex];\n let testValue = frontMatrix[testRowIndex - 1][testColumnIndex - 1];\n if (Math.abs(testValue) > Math.abs(pivotValue)) {\n pivotValue = testValue;\n pivotColumnIndex = testColumnIndex;\n pivotRowIndex = testRowIndex;\n }\n }\n }\n }\n\n let pivotGlobalRowIndex = Math.abs(rowHeaders[pivotRowIndex - 1]);\n pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[pivotColumnIndex - 1]); // Assign, don't declare\n let permutationHelper =\n pivotGlobalRowIndex +\n pivotColumnGlobalIndex +\n rowSwapCount[pivotGlobalRowIndex - 1] +\n columnSwapCount[pivotColumnGlobalIndex - 1];\n frontalState.determinant =\n (frontalState.determinant * pivotValue * (-1) ** permutationHelper) / Math.abs(pivotValue);\n\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n if (nodeIndex >= pivotGlobalRowIndex) rowSwapCount[nodeIndex]--;\n if (nodeIndex >= pivotColumnGlobalIndex) columnSwapCount[nodeIndex]--;\n }\n\n if (Math.abs(pivotValue) < 1e-10) {\n errorLog(\n `Matrix singular or ill-conditioned, currentElementIndex=${elementData.currentElementIndex}, pivotGlobalRowIndex=${pivotGlobalRowIndex}, pivotColumnGlobalIndex=${pivotColumnGlobalIndex}, pivotValue=${pivotValue}`\n );\n }\n\n if (pivotValue === 0) return;\n\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.pivotRow[columnIndex] = frontMatrix[pivotRowIndex - 1][columnIndex] / pivotValue;\n }\n\n let rightHandSide = frontalData.globalResidualVector[pivotGlobalRowIndex - 1] / pivotValue;\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] = rightHandSide;\n pivotColumn[pivotRowIndex - 1] = pivotValue;\n\n if (pivotRowIndex > 1) {\n for (let rowIndex = 0; rowIndex < pivotRowIndex - 1; rowIndex++) {\n let globalRowIndex = Math.abs(rowHeaders[rowIndex]);\n let eliminationFactor = frontMatrix[rowIndex][pivotColumnIndex - 1];\n pivotColumn[rowIndex] = eliminationFactor;\n if (pivotColumnIndex > 1 && eliminationFactor !== 0) {\n for (let columnIndex = 0; columnIndex < pivotColumnIndex - 1; columnIndex++) {\n frontMatrix[rowIndex][columnIndex] -= eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n if (pivotColumnIndex < columnCount) {\n for (let columnIndex = pivotColumnIndex; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex][columnIndex - 1] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n frontalData.globalResidualVector[globalRowIndex - 1] -= eliminationFactor * rightHandSide;\n }\n }\n\n if (pivotRowIndex < rowCount) {\n for (let rowIndex = pivotRowIndex; rowIndex < rowCount; rowIndex++) {\n let globalRowIndex = Math.abs(rowHeaders[rowIndex]);\n let eliminationFactor = frontMatrix[rowIndex][pivotColumnIndex - 1];\n pivotColumn[rowIndex] = eliminationFactor;\n if (pivotColumnIndex > 1) {\n for (let columnIndex = 0; columnIndex < pivotColumnIndex - 1; columnIndex++) {\n frontMatrix[rowIndex - 1][columnIndex] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n if (pivotColumnIndex < columnCount) {\n for (let columnIndex = pivotColumnIndex; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex - 1][columnIndex - 1] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n frontalData.globalResidualVector[globalRowIndex - 1] -= eliminationFactor * rightHandSide;\n }\n }\n\n for (let i = 0; i < rowCount; i++) {\n frontStorage.pivotData[pivotDataIndex + i - 1] = pivotColumn[i];\n }\n pivotDataIndex += rowCount;\n\n for (let i = 0; i < rowCount; i++) {\n frontStorage.pivotData[pivotDataIndex + i - 1] = rowHeaders[i];\n }\n pivotDataIndex += rowCount;\n\n frontStorage.pivotData[pivotDataIndex - 1] = pivotRowIndex;\n pivotDataIndex++;\n\n for (let i = 0; i < columnCount; i++) {\n frontStorage.frontValues[frontDataCounter - 1 + i] = frontStorage.pivotRow[i];\n }\n frontDataCounter += columnCount;\n\n for (let i = 0; i < columnCount; i++) {\n frontStorage.frontValues[frontDataCounter - 1 + i] = frontStorage.columnHeaders[i];\n }\n frontDataCounter += columnCount;\n\n frontStorage.frontValues[frontDataCounter - 1] = pivotGlobalRowIndex;\n frontStorage.frontValues[frontDataCounter] = columnCount;\n frontStorage.frontValues[frontDataCounter + 1] = pivotColumnIndex;\n frontStorage.frontValues[frontDataCounter + 2] = pivotValue;\n frontDataCounter += 4;\n\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n frontMatrix[rowIndex][columnCount - 1] = 0;\n }\n\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowCount - 1][columnIndex] = 0;\n }\n\n columnCount--;\n if (pivotColumnIndex < columnCount + 1) {\n for (let columnIndex = pivotColumnIndex - 1; columnIndex < columnCount; columnIndex++) {\n frontStorage.columnHeaders[columnIndex] = frontStorage.columnHeaders[columnIndex + 1];\n }\n }\n\n rowCount--;\n if (pivotRowIndex < rowCount + 1) {\n for (let rowIndex = pivotRowIndex - 1; rowIndex < rowCount; rowIndex++) {\n rowHeaders[rowIndex] = rowHeaders[rowIndex + 1];\n }\n }\n\n if (rowCount > 1 || elementData.currentElementIndex < totalElements) continue;\n\n pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[0]); // Assign, don't declare\n pivotRowIndex = 1;\n pivotValue = frontMatrix[0][0];\n pivotGlobalRowIndex = Math.abs(rowHeaders[0]);\n pivotColumnIndex = 1;\n permutationHelper =\n pivotGlobalRowIndex +\n pivotColumnGlobalIndex +\n rowSwapCount[pivotGlobalRowIndex - 1] +\n columnSwapCount[pivotColumnGlobalIndex - 1];\n frontalState.determinant =\n (frontalState.determinant * pivotValue * (-1) ** permutationHelper) / Math.abs(pivotValue);\n\n frontStorage.pivotRow[0] = 1;\n if (Math.abs(pivotValue) < 1e-10) {\n errorLog(\n `Matrix singular or ill-conditioned, currentElementIndex=${elementData.currentElementIndex}, pivotGlobalRowIndex=${pivotGlobalRowIndex}, pivotColumnGlobalIndex=${pivotColumnGlobalIndex}, pivotValue=${pivotValue}`\n );\n }\n\n if (pivotValue === 0) return;\n\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] =\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] / pivotValue;\n frontStorage.frontValues[frontDataCounter - 1] = frontStorage.pivotRow[0];\n frontDataCounter++;\n frontStorage.frontValues[frontDataCounter - 1] = frontStorage.columnHeaders[0];\n frontDataCounter++;\n frontStorage.frontValues[frontDataCounter - 1] = pivotGlobalRowIndex;\n frontStorage.frontValues[frontDataCounter] = columnCount;\n frontStorage.frontValues[frontDataCounter + 1] = pivotColumnIndex;\n frontStorage.frontValues[frontDataCounter + 2] = pivotValue;\n frontDataCounter += 4;\n\n frontStorage.pivotData[pivotDataIndex - 1] = pivotColumn[0];\n pivotDataIndex++;\n frontStorage.pivotData[pivotDataIndex - 1] = rowHeaders[0];\n pivotDataIndex++;\n frontStorage.pivotData[pivotDataIndex - 1] = pivotRowIndex;\n pivotDataIndex++;\n\n frontalState.frontDataIndex = frontDataCounter;\n if (frontalState.writeFlag === 1)\n debugLog(`total ecs transfer in matrix reduction=${frontDataCounter}`);\n\n // Back substitution\n performBackSubstitution(frontDataCounter);\n break;\n }\n }\n}\n\n/**\n * Function to perform back substitution for the frontal solver\n * @param {number} frontDataCounter - Index counter for the element contributions\n */\nfunction performBackSubstitution(frontDataCounter) {\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n frontalState.globalSolutionVector[nodeIndex] = frontalData.boundaryValues[nodeIndex];\n }\n\n for (let iterationIndex = 1; iterationIndex <= frontalState.totalNodes; iterationIndex++) {\n frontDataCounter -= 4;\n let pivotGlobalRowIndex = frontStorage.frontValues[frontDataCounter - 1];\n let columnCount = frontStorage.frontValues[frontDataCounter];\n let pivotColumnIndex = frontStorage.frontValues[frontDataCounter + 1];\n let pivotValue = frontStorage.frontValues[frontDataCounter + 2];\n\n if (iterationIndex === 1) {\n frontDataCounter--;\n frontStorage.columnHeaders[0] = frontStorage.frontValues[frontDataCounter - 1];\n frontDataCounter--;\n frontStorage.pivotRow[0] = frontStorage.frontValues[frontDataCounter - 1];\n } else {\n frontDataCounter -= columnCount;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.columnHeaders[columnIndex] =\n frontStorage.frontValues[frontDataCounter - 1 + columnIndex];\n }\n frontDataCounter -= columnCount;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.pivotRow[columnIndex] = frontStorage.frontValues[frontDataCounter - 1 + columnIndex];\n }\n }\n\n let pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[pivotColumnIndex - 1]);\n if (frontalData.nodeConstraintCode[pivotColumnGlobalIndex - 1] > 0) continue;\n\n let accumulatedValue = 0;\n frontStorage.pivotRow[pivotColumnIndex - 1] = 0;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n accumulatedValue -=\n frontStorage.pivotRow[columnIndex] *\n frontalState.globalSolutionVector[Math.abs(frontStorage.columnHeaders[columnIndex]) - 1];\n }\n\n frontalState.globalSolutionVector[pivotColumnGlobalIndex - 1] =\n accumulatedValue + frontalData.globalResidualVector[pivotGlobalRowIndex - 1];\n\n frontalData.nodeConstraintCode[pivotColumnGlobalIndex - 1] = 1;\n }\n\n if (frontalState.writeFlag === 1)\n debugLog(`value of frontDataCounter after backsubstitution=${frontDataCounter}`);\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 { runFrontalSolver } from \"./frontalSolverScript.js\";\nimport { assembleFrontPropagationFront } from \"../solvers/frontPropagationScript.js\";\n\n/**\n * Function to solve a system of non-linear equations using the Newton-Raphson method\n * @param {function} assembleMat - Matrix assembler based on the physical model\n * @param {object} context - Context object containing simulation data and options\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\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 // Check if using frontal solver\n if (context.solverMethod === \"frontal\") {\n const frontalResult = runFrontalSolver(\n assembleFrontPropagationFront,\n context.meshData,\n context.boundaryConditions,\n { solutionVector, eikonalActivationFlag: context.eikonalActivationFlag }\n );\n deltaX = frontalResult.solutionVector;\n } else {\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\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 * @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 { assembleGeneralFormPDEMat, assembleGeneralFormPDEFront } from \"./solvers/generalFormPDEScript.js\";\nimport { assembleHeatConductionMat, assembleHeatConductionFront } from \"./solvers/heatConductionScript.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 this.coefficientFunctions = null; // Add storage for coefficient functions\n basicLog(\"FEAScriptModel instance created\");\n }\n\n /**\n * Sets the solver configuration\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} [options] - Optional additional configuration\n */\n setSolverConfig(solverConfig, options = {}) {\n this.solverConfig = solverConfig;\n\n // Store coefficient functions if provided\n if (options && options.coefficientFunctions) {\n this.coefficientFunctions = options.coefficientFunctions;\n debugLog(\"Coefficient functions set\");\n }\n\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 /**\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\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 === \"heatConductionScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Check if using frontal solver\n if (this.solverMethod === \"frontal\") {\n const frontalResult = runFrontalSolver(\n assembleHeatConductionFront,\n meshData,\n this.boundaryConditions\n );\n solutionVector = frontalResult.solutionVector;\n } else {\n // Use regular linear solver methods\n ({ jacobianMatrix, residualVector } = assembleHeatConductionMat(meshData, this.boundaryConditions));\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 } else if (this.solverConfig === \"generalFormPDEScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n // Check if using frontal solver\n if (this.solverMethod === \"frontal\") {\n errorLog(\n \"Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.\"\n );\n } else {\n // Use regular linear solver methods\n ({ jacobianMatrix, residualVector } = assembleGeneralFormPDEMat(\n meshData,\n this.boundaryConditions,\n this.coefficientFunctions\n ));\n\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\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 { initializeFEA, performIsoparametricMapping1D } from \"../mesh/meshUtilsScript.js\";\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the Jacobian matrix and residuals vector for the general form PDE model\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions\n * @param {object} coefficientFunctions - Functions A(x), B(x), C(x), D(x) for the PDE\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n */\nexport function assembleGeneralFormPDEMat(meshData, boundaryConditions, coefficientFunctions) {\n basicLog(\"Starting general form PDE 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 // Extract coefficient functions\n const { A, B, C, D } = coefficientFunctions;\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 if (meshDimension === \"1D\") {\n // 1D general form PDE\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 // Convert to 0-based indexing\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex = 0; gaussPointIndex < gaussPoints.length; gaussPointIndex++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < numNodes; i++) {\n xCoord += nodesXCoordinates[localToGlobalMap[i]] * basisFunction[i];\n }\n\n // Evaluate coefficient functions at this physical coordinate\n const a = A(xCoord);\n const b = B(xCoord);\n const c = C(xCoord);\n const d = D(xCoord);\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n const globalNodeIndex1 = localToGlobalMap[localNodeIndex1];\n\n // Source term contribution to residual vector\n residualVector[globalNodeIndex1] -=\n gaussWeights[gaussPointIndex] * detJacobian * d * basisFunction[localNodeIndex1];\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n const globalNodeIndex2 = localToGlobalMap[localNodeIndex2];\n\n // Diffusion term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n a *\n basisFunctionDerivX[localNodeIndex1] *\n basisFunctionDerivX[localNodeIndex2];\n\n // Advection term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n b *\n basisFunctionDerivX[localNodeIndex2] *\n basisFunction[localNodeIndex1];\n\n // Reaction term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n c *\n basisFunction[localNodeIndex1] *\n basisFunction[localNodeIndex2];\n }\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n errorLog(\"2D general form PDE is not yet supported in assembleGeneralFormPDEMat.\");\n // 2D general form PDE - empty for now\n }\n\n // Apply boundary conditions\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Apply Dirichlet boundary conditions only\n genericBoundaryConditions.imposeDirichletBoundaryConditions(residualVector, jacobianMatrix);\n\n basicLog(\"General form PDE matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n\n/**\n * Function to assemble the frontal solver matrix for the general form PDE model\n * @param {object} data - Object containing element data for the frontal solver\n * @returns {object} An object containing local Jacobian matrix and residual vector\n */\nexport function assembleGeneralFormPDEFront({\n elementIndex,\n nop,\n meshData,\n basisFunctions,\n FEAData,\n coefficientFunctions,\n}) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n const { A, B, C, D } = coefficientFunctions;\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n if (meshDimension === \"1D\") {\n // 1D general form PDE\n\n // Loop over Gauss points\n for (let gaussPointIndex = 0; gaussPointIndex < gaussPoints.length; gaussPointIndex++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < numNodes; i++) {\n xCoord += nodesXCoordinates[localToGlobalMap[i]] * basisFunction[i];\n }\n\n // Evaluate coefficient functions at this physical coordinate\n const a = A(xCoord);\n const b = B(xCoord);\n const c = C(xCoord);\n const d = D(xCoord);\n\n // Computation of local Jacobian matrix and residual vector\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n // Source term contribution to local residual vector\n localResidualVector[localNodeIndex1] -=\n gaussWeights[gaussPointIndex] * detJacobian * d * basisFunction[localNodeIndex1];\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n // Diffusion term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n a *\n basisFunctionDerivX[localNodeIndex1] *\n basisFunctionDerivX[localNodeIndex2];\n\n // Advection term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n b *\n basisFunctionDerivX[localNodeIndex2] *\n basisFunction[localNodeIndex1];\n\n // Reaction term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n c *\n basisFunction[localNodeIndex1] *\n basisFunction[localNodeIndex2];\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n errorLog(\"2D general form PDE is not yet supported in assembleGeneralFormPDEFront.\");\n // 2D general form PDE - empty for now\n }\n\n return {\n localJacobianMatrix,\n localResidualVector,\n ngl,\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\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// | ____| ____| /\\ / ____| (_) | | //\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 } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const printVersion = \"0.1.3\";"],"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","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","nodesXCoordinates","totalNodesX","deltaX","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","meshData","totalNodes","colIndex","basisFunctions","gaussPointsAndWeights","localToGlobalMap","numNodes","performIsoparametricMapping1D","params","xCoordinates","ksiDerivX","localNodeIndex","detJacobian","basisFunctionDerivX","performIsoparametricMapping2D","yCoordinates","etaDerivX","ksiDerivY","etaDerivY","basisFunctionDerivY","ThermalBoundaryConditions","boundaryConditions","imposeConstantTempBoundaryConditions","Object","keys","boundaryKey","tempValue","globalNodeIndex","imposeConstantTempBoundaryConditionsFront","nodeConstraintCode","boundaryValues","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","basisFunctionsAndDerivatives","tangentVectorLength","localNodeIndex2","globalNodeIndex2","gaussPointIndex","imposeConvectionBoundaryConditionsFront","localJacobianMatrix","map","localResidualVector","boundaryElement","find","_","assembleHeatConductionFront","FEAData","ngl","gaussPointIndex1","localNodeIndex1","gaussPointIndex2","globalIndex","GenericBoundaryConditions","imposeDirichletBoundaryConditions","value","imposeConstantValueBoundaryConditionsFront","assembleFrontPropagationMat","eikonalActivationFlag","eikonalViscousTerm","totalElements","mappingResult","solutionDerivX","solutionDerivY","localToGlobalMap1","localToGlobalMap2","assembleFrontPropagationFront","frontalData","frontalState","elementData","currentElementIndex","frontStorage","runFrontalSolver","assembleFront","numElements","globalResidualVector","topologyData","lateralData","writeFlag","transformationFlag","nodesPerElement","determinant","systemSize","globalSolutionVector","frontDataIndex","frontSize","frontWidthEstimate","ceil","estimateFrontSize","frontValues","columnHeaders","pivotRow","pivotData","initializeFrontalArrays","dirichletBoundaryConditionsHandler","currentSolutionVector","thermalBoundaryConditions","pivotColumnGlobalIndex","localDestination","rowDestination","rowHeaders","pivotRowIndices","pivotColumnIndices","modifiedRows","pivotColumn","frontMatrix","rowSwapCount","columnSwapCount","lastAppearanceCheck","frontDataCounter","pivotDataIndex","summedRows","reverseElementIndex","columnCount","rowCount","assembled","numElementNodes","numElementColumns","assembleElementContribution","currentElement","columnIndex","rowIndex","localColumnIndex","frontColumnIndex","localRowIndex","availableColumnCount","constrainedRowCount","availableRowCount","absoluteNodeIndex","constrainedIndex","pivotRowIndex","pivotColumnIndex","pivotValue","testColumnIndex","testRowIndex","testValue","pivotGlobalRowIndex","permutationHelper","rightHandSide","globalRowIndex","eliminationFactor","performBackSubstitution","runFrontalAlgorithm","toExponential","finalNodesX","finalNodesY","slice","nodesCoordinates","boundaryLocalJacobianMatrix","boundaryResidualVector","isOnRobinTypeBoundary","some","result","localNodeI","localNodeJ","iterationIndex","accumulatedValue","newtonRaphson","assembleMat","context","errorNorm","initialSolution","Number","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","meshConfig","coefficientFunctions","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","mesh","nodesCoordinatesAndNumbering","prepareMesh","assembleHeatConductionMat","eikonalExteralIterations","newtonRaphsonResult","A","B","C","D","xCoord","a","b","d","globalNodeIndex1","assembleGeneralFormPDEMat","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","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","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","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"],"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/mesh/basisFunctionsScript.js","../src/mesh/meshGenerationScript.js","../src/methods/numericalIntegrationScript.js","../src/mesh/meshUtilsScript.js","../src/solvers/thermalBoundaryConditionsScript.js","../src/solvers/heatConductionScript.js","../src/solvers/genericBoundaryConditionsScript.js","../src/solvers/frontPropagationScript.js","../src/methods/frontalSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/vendor/comlink.mjs","../src/FEAScript.js","../src/solvers/generalFormPDEScript.js","../src/workers/workerScript.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.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 printVersionInformation() {\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 errorLog(`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 { 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 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/**\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 * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\n imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix) {\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 constant temperature boundary conditions for the frontal solver\n * @param {array} nodeConstraintCode - Array indicating boundary condition code for each node\n * @param {array} boundaryValues - Array containing boundary condition values\n */\n imposeConstantTempBoundaryConditionsFront(nodeConstraintCode, boundaryValues) {\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\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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\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\n // Set boundary condition code and value\n nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = tempValue;\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 // 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 * Function to impose convection boundary conditions for the frontal solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nodesXCoordinates - Array of x-coordinates of nodes\n * @param {array} nodesYCoordinates - Array of y-coordinates of nodes\n * @param {array} gaussPoints - Array of Gauss points for numerical integration\n * @param {array} gaussWeights - Array of Gauss weights for numerical integration\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @returns {object} An object containing:\n * - localJacobianMatrix: Local Jacobian matrix with convection contributions\n * - localResidualVector: Residual vector with convection contributions\n */\n imposeConvectionBoundaryConditionsFront(\n elementIndex,\n nodesXCoordinates,\n nodesYCoordinates,\n gaussPoints,\n gaussWeights,\n basisFunctions\n ) {\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 // Initialize local Jacobian matrix and local residual vector\n const numNodes = this.nop[elementIndex].length;\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Check if this element is on a convection boundary\n for (const boundaryKey in this.boundaryElements) {\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\n // Find if this element is on this boundary and which side\n const boundaryElement = this.boundaryElements[boundaryKey].find(\n ([elemIdx, _]) => elemIdx === elementIndex\n );\n\n if (boundaryElement) {\n const side = boundaryElement[1];\n\n if (this.meshDimension === \"1D\") {\n // Handle 1D case\n let nodeIndex;\n if (this.elementOrder === \"linear\") {\n nodeIndex = side === 0 ? 0 : 1;\n } else if (this.elementOrder === \"quadratic\") {\n nodeIndex = side === 0 ? 0 : 2;\n }\n\n // Add contribution to local Jacobian matrix and local residual vector\n debugLog(\n ` - Applied convection boundary condition to node ${nodeIndex + 1} (element ${\n elementIndex + 1\n }, local node ${nodeIndex + 1})`\n );\n localResidualVector[nodeIndex] += -convectionCoeff * extTemp;\n localJacobianMatrix[nodeIndex][nodeIndex] += convectionCoeff;\n } else if (this.meshDimension === \"2D\") {\n // Handle 2D case\n if (this.elementOrder === \"linear\") {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n\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 // Get basis functions\n const basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(gaussPoint1, gaussPoint2);\n const basisFunction = basisFunctionsAndDerivatives.basisFunction;\n const basisFunctionDerivKsi = basisFunctionsAndDerivatives.basisFunctionDerivKsi;\n const basisFunctionDerivEta = basisFunctionsAndDerivatives.basisFunctionDerivEta;\n\n // Calculate tangent vector components\n let ksiDerivX = 0,\n ksiDerivY = 0,\n etaDerivX = 0,\n etaDerivY = 0;\n for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {\n const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1;\n\n if (side === 0 || side === 2) {\n ksiDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n ksiDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivKsi[nodeIndex];\n } else if (side === 1 || side === 3) {\n etaDerivX += nodesXCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n etaDerivY += nodesYCoordinates[globalNodeIndex] * basisFunctionDerivEta[nodeIndex];\n }\n }\n\n // Compute tangent vector length\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 // Apply boundary conditions to local matrices\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n localResidualVector[localNodeIndex] +=\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 localJacobianMatrix[localNodeIndex][localNodeIndex2] +=\n -gaussWeights[0] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n } else if (this.elementOrder === \"quadratic\") {\n // Handle quadratic elements (similar pattern but with more Gauss points)\n for (let gaussPointIndex = 0; gaussPointIndex < 3; gaussPointIndex++) {\n let gaussPoint1, gaussPoint2, firstNodeIndex, lastNodeIndex, nodeIncrement;\n\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 // Apply boundary conditions to local matrices\n for (\n let localNodeIndex = firstNodeIndex;\n localNodeIndex < lastNodeIndex;\n localNodeIndex += nodeIncrement\n ) {\n localResidualVector[localNodeIndex] +=\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 localJacobianMatrix[localNodeIndex][localNodeIndex2] +=\n -gaussWeights[gaussPointIndex] *\n tangentVectorLength *\n basisFunction[localNodeIndex] *\n basisFunction[localNodeIndex2] *\n convectionCoeff;\n }\n }\n }\n }\n }\n }\n }\n }\n\n return { localJacobianMatrix, localResidualVector };\n }\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 *\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\nexport function assembleHeatConductionMat(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 const 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 const 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 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\n // Impose ConstantTemp boundary conditions\n thermalBoundaryConditions.imposeConstantTempBoundaryConditions(residualVector, jacobianMatrix);\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 residual vector for the solid heat transfer model when using the frontal system solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nop - Nodal connectivity array (element-to-node mapping)\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @param {object} FEAData - Object containing FEA-related data\n * @returns {object} An object containing:\n * - localJacobianMatrix: Local Jacobian matrix\n * - localResidualVector: Residual vector contributions\n * - ngl: Array mapping local node indices to global node indices\n */\nexport function assembleHeatConductionFront({ elementIndex, nop, meshData, basisFunctions, FEAData }) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n // Loop over Gauss points\n if (meshDimension === \"1D\") {\n // 1D solid heat transfer\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex1]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n gaussWeights[gaussPointIndex1] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2]);\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n // 2D solid heat transfer\n for (let gaussPointIndex1 = 0; gaussPointIndex1 < gaussPoints.length; gaussPointIndex1++) {\n for (let gaussPointIndex2 = 0; gaussPointIndex2 < gaussPoints.length; gaussPointIndex2++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } =\n basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1], gaussPoints[gaussPointIndex2]);\n\n // Create mapping from local element space to global mesh (convert to 0-based indexing)\n const localToGlobalMap = ngl.map((globalIndex) => globalIndex - 1);\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\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 return { localJacobianMatrix, localResidualVector, ngl };\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 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 Dirichlet boundary conditions\n * @param {array} residualVector - The residual vector to be modified\n * @param {array} jacobianMatrix - The Jacobian matrix to be modified\n *\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\n */\n imposeDirichletBoundaryConditions(residualVector, jacobianMatrix) {\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 value\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 value\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 value\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 value\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 * Function to impose constant value (Dirichlet) boundary conditions for the frontal solver\n * @param {array} nodeConstraintCode - Array indicating boundary condition code for each node\n * @param {array} boundaryValues - Array containing boundary condition values\n */\n imposeConstantValueBoundaryConditionsFront(nodeConstraintCode, boundaryValues) {\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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 nodeConstraintCode[globalNodeIndex] = 1;\n boundaryValues[globalNodeIndex] = value;\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// Base viscous term that remains when eikonal equation is fully activated\nconst baseEikonalViscousTerm = 1e-2;\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 let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n debugLog(`eikonalViscousTerm: ${eikonalViscousTerm}`);\n debugLog(`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 // Unsupported 1D front propagation\n errorLog(\"1D front propagation is not yet supported\");\n\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 // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // jacobianMatrix\n // TODO 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 eikonalActivationFlag *\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 const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Impose Dirichlet boundary conditions\n genericBoundaryConditions.imposeDirichletBoundaryConditions(residualVector, jacobianMatrix);\n basicLog(\"Front propagation matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n\n/**\n * Function to assemble the local Jacobian matrix and residual vector for the front propagation model when using the frontal system solver\n * @param {number} elementIndex - Index of the element being processed\n * @param {array} nop - Nodal connectivity array (element-to-node mapping)\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} basisFunctions - Object containing basis functions and their derivatives\n * @param {object} FEAData - Object containing FEA-related data\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 * - localJacobianMatrix: Local Jacobian matrix\n * - residualVector: Residual vector contributions\n * - ngl: Array mapping local node indices to global node indices\n */\nexport function assembleFrontPropagationFront({\n elementIndex,\n nop,\n meshData,\n basisFunctions,\n FEAData,\n solutionVector,\n eikonalActivationFlag,\n}) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n\n // Calculate eikonal viscous term\n let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(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 // Unsupported 1D front propagation\n errorLog(\"1D front propagation is not yet supported\");\n\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 // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n let localToGlobalMap2 = localToGlobalMap[localNodeIndex2];\n // localJacobianMatrix\n // TODO localJacobianMatrix 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 // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi, basisFunctionDerivEta } =\n basisFunctions.getBasisFunctions(gaussPoints[gaussPointIndex1], gaussPoints[gaussPointIndex2]);\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = performIsoparametricMapping2D({\n basisFunction,\n basisFunctionDerivKsi,\n basisFunctionDerivEta,\n nodesXCoordinates,\n nodesYCoordinates,\n localToGlobalMap,\n numNodes,\n });\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 // Viscous term contribution\n localResidualVector[localNodeIndex1] +=\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 // Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n localResidualVector[localNodeIndex1] +=\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 // Viscous term contribution\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n eikonalViscousTerm *\n gaussWeights[gaussPointIndex1] *\n gaussWeights[gaussPointIndex2] *\n detJacobian *\n (basisFunctionDerivX[localNodeIndex1] * basisFunctionDerivX[localNodeIndex2] +\n basisFunctionDerivY[localNodeIndex1] * basisFunctionDerivY[localNodeIndex2]);\n\n // Eikonal equation contribution\n if (eikonalActivationFlag !== 0) {\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] +=\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 eikonalActivationFlag *\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 return { localJacobianMatrix, localResidualVector, ngl };\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 { initializeFEA } from \"../mesh/meshUtilsScript.js\";\nimport { assembleHeatConductionFront } from \"../solvers/heatConductionScript.js\";\nimport { ThermalBoundaryConditions } from \"../solvers/thermalBoundaryConditionsScript.js\";\nimport { assembleFrontPropagationFront } from \"../solvers/frontPropagationScript.js\";\nimport { GenericBoundaryConditions } from \"../solvers/genericBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n// Create object templates\nconst frontalData = {};\nconst frontalState = {};\nconst elementData = { currentElementIndex: 0 };\nconst frontStorage = {};\nlet basisFunctions;\n\n/**\n * Function to run the frontal solver and obtain results for plotting\n * @param {function} assembleFront - Matrix assembler based on the physical model\n * @param {object} meshData - Object containing mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions\n * @param {object} [options] - Additional options for the solver\n * @returns {object} An object containing the solution vector and node coordinates\n */\nexport function runFrontalSolver(assembleFront, meshData, boundaryConditions, options = {}) {\n // Initialize FEA components\n const FEAData = initializeFEA(meshData);\n const totalNodes = meshData.nodesXCoordinates.length;\n const numElements = meshData.totalElements;\n const numNodes = FEAData.numNodes;\n\n // Calculate required array sizes\n initializeFrontalArrays(numNodes, numElements);\n\n // Start timing for system solving (frontal algorithm)\n basicLog(\"Solving system using frontal...\");\n console.time(\"systemSolving\");\n\n // Initialize basis functions\n basisFunctions = new BasisFunctions({\n meshDimension: meshData.meshDimension,\n elementOrder: meshData.elementOrder,\n });\n\n // Copy node connectivity array into frontalData storage\n for (let elementIndex = 0; elementIndex < meshData.totalElements; elementIndex++) {\n for (let nodeIndex = 0; nodeIndex < FEAData.numNodes; nodeIndex++) {\n frontalData.nodalNumbering[elementIndex][nodeIndex] = meshData.nop[elementIndex][nodeIndex];\n }\n }\n\n // Apply Dirichlet-type boundary conditions\n // Initialize all nodes with no boundary condition\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.nodeConstraintCode[nodeIndex] = 0;\n frontalData.boundaryValues[nodeIndex] = 0;\n }\n\n // Handle Dirichlet-type boundary conditions differently based on which solver is being used\n let dirichletBoundaryConditionsHandler;\n // Solid heat transfer model (heatConductionScript solver)\n if (assembleFront === assembleHeatConductionFront) {\n dirichletBoundaryConditionsHandler = new ThermalBoundaryConditions(\n boundaryConditions,\n meshData.boundaryElements,\n meshData.nop,\n meshData.meshDimension,\n meshData.elementOrder\n );\n\n dirichletBoundaryConditionsHandler.imposeConstantTempBoundaryConditionsFront(\n frontalData.nodeConstraintCode,\n frontalData.boundaryValues\n );\n // Front propagation model (frontPropagationScript solver)\n } else if (assembleFront === assembleFrontPropagationFront) {\n dirichletBoundaryConditionsHandler = new GenericBoundaryConditions(\n boundaryConditions,\n meshData.boundaryElements,\n meshData.nop,\n meshData.meshDimension,\n meshData.elementOrder\n );\n\n dirichletBoundaryConditionsHandler.imposeConstantValueBoundaryConditionsFront(\n frontalData.nodeConstraintCode,\n frontalData.boundaryValues\n );\n }\n // Initialize global residual vector\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.globalResidualVector[nodeIndex] = 0;\n }\n\n frontalState.totalNodes = meshData.nodesXCoordinates.length;\n frontalState.writeFlag = 0;\n frontalState.transformationFlag = 1;\n frontalState.determinant = 1;\n\n for (let elementIndex = 0; elementIndex < meshData.totalElements; elementIndex++) {\n frontalState.nodesPerElement[elementIndex] = FEAData.numNodes;\n }\n\n // Parameters for non-linear assemblers\n frontalState.currentSolutionVector = options.solutionVector;\n frontalState.eikonalActivationFlag = options.eikonalActivationFlag;\n\n // Pass assembleFront and dirichletBoundaryConditionsHandler to runFrontalAlgorithm\n runFrontalAlgorithm(meshData, FEAData, dirichletBoundaryConditionsHandler, assembleFront);\n\n // Copy solution\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n frontalData.solutionVector[nodeIndex] = frontalState.globalSolutionVector[nodeIndex];\n }\n\n // Output results to console for debugging\n const { nodesXCoordinates, nodesYCoordinates } = meshData;\n for (let nodeIndex = 0; nodeIndex < meshData.nodesXCoordinates.length; nodeIndex++) {\n if (meshData.meshDimension === \"1D\") {\n // 1D case - only output X coordinates and temperature\n debugLog(\n `${nodesXCoordinates[nodeIndex].toExponential(5)} ${frontalData.solutionVector[\n nodeIndex\n ].toExponential(5)}`\n );\n } else {\n // 2D case - output X, Y coordinates and temperature\n debugLog(\n `${nodesXCoordinates[nodeIndex].toExponential(5)} ${nodesYCoordinates[nodeIndex].toExponential(\n 5\n )} ${frontalData.solutionVector[nodeIndex].toExponential(5)}`\n );\n }\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(\"System solved successfully\");\n\n const { nodesXCoordinates: finalNodesX, nodesYCoordinates: finalNodesY } = meshData;\n return {\n solutionVector: frontalData.solutionVector.slice(0, totalNodes),\n nodesCoordinates: {\n nodesXCoordinates: finalNodesX,\n nodesYCoordinates: finalNodesY,\n },\n };\n}\n\n/**\n * Function to initialize arrays dynamically based on problem size\n * @param {number} numNodes - Number of nodes per element\n * @param {number} numElements - Number of elements in the mesh\n */\nfunction initializeFrontalArrays(numNodes, numElements) {\n // Use the actual number of elements from the mesh\n frontalData.nodalNumbering = Array(numElements)\n .fill()\n .map(() => Array(numNodes).fill(0));\n frontalData.nodeConstraintCode = Array(numNodes).fill(0);\n frontalData.boundaryValues = Array(numNodes).fill(0);\n frontalData.globalResidualVector = Array(numNodes).fill(0);\n frontalData.solutionVector = Array(numNodes).fill(0);\n frontalData.topologyData = Array(numElements).fill(0);\n frontalData.lateralData = Array(numElements).fill(0);\n\n // Initialize frontalState arrays\n frontalState.writeFlag = 0;\n frontalState.totalNodes = numNodes;\n frontalState.transformationFlag = 0;\n frontalState.nodesPerElement = Array(numElements).fill(0);\n frontalState.determinant = 1;\n\n // For matrix operations, estimate required size based on problem complexity\n const systemSize = Math.max(numNodes, 2000);\n frontalState.globalSolutionVector = Array(systemSize).fill(0);\n frontalState.frontDataIndex = 0;\n\n // Initialize elementData arrays\n elementData.localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n elementData.currentElementIndex = 0;\n\n // Initialize frontStorage arrays\n const frontSize = estimateFrontSize(numNodes, numElements);\n frontStorage.frontValues = Array(frontSize).fill(0);\n frontStorage.columnHeaders = Array(systemSize).fill(0);\n frontStorage.pivotRow = Array(systemSize).fill(0);\n frontStorage.pivotData = Array(frontSize).fill(0);\n}\n\n/**\n * Function to estimate the required front size\n * @param {number} numNodes - Number of of nodes per element\n * @param {number} numElements - Number of elements in the mesh\n * @returns {number} Estimated front size\n */\nfunction estimateFrontSize(numNodes, numElements) {\n const frontWidthEstimate = Math.max(Math.ceil(Math.sqrt(numElements)) * numNodes, numNodes * 2);\n return frontWidthEstimate * numElements;\n}\n// Old function to estimate the required front size\n// function estimateFrontSize(numNodes, numElements, numNodes) {\n// const frontWidthEstimate = Math.ceil(Math.sqrt(numElements) * numNodes * 2);\n// const frontSize = frontWidthEstimate * numNodes * 4;\n// return Math.max(frontSize, 10000);\n// }\n\n/**\n * Function to compute local Jacobian matrix and local residual vector\n * @param {object} meshData - Object containing mesh data\n * @param {object} FEAData - Object containing FEA-related data\n * @param {object} thermalBoundaryConditions - Object containing thermal boundary conditions\n * @param {function} assembleFront - Matrix assembler based on the physical model\n */\nfunction assembleElementContribution(meshData, FEAData, thermalBoundaryConditions, assembleFront) {\n const elementIndex = elementData.currentElementIndex - 1;\n\n // Guard against out-of-range indices\n if (elementIndex < 0 || elementIndex >= meshData.totalElements) {\n errorLog(`Skipping out-of-range elementIndex=${elementIndex} (totalElements=${meshData.totalElements})`);\n return false;\n }\n\n // Domain terms\n const { localJacobianMatrix, localResidualVector, ngl } = assembleFront({\n elementIndex,\n nop: frontalData.nodalNumbering,\n meshData,\n basisFunctions: basisFunctions,\n FEAData,\n // These are ignored by linear assemblers\n solutionVector: frontalState.currentSolutionVector,\n eikonalActivationFlag: frontalState.eikonalActivationFlag,\n });\n\n // Handle Robin-type boundary conditions differently based on which solver is being used\n let boundaryLocalJacobianMatrix = Array(FEAData.numNodes)\n .fill()\n .map(() => Array(FEAData.numNodes).fill(0));\n let boundaryResidualVector = Array(FEAData.numNodes).fill(0);\n\n // heatConductionScript solver\n if (assembleFront === assembleHeatConductionFront) {\n // Check if this element is on a Robin-type boundary\n let isOnRobinTypeBoundary = false;\n for (const boundaryKey in meshData.boundaryElements) {\n if (\n thermalBoundaryConditions.boundaryConditions[boundaryKey]?.[0] === \"convection\" &&\n meshData.boundaryElements[boundaryKey].some(([elemIdx, _]) => elemIdx === elementIndex)\n ) {\n isOnRobinTypeBoundary = true;\n break;\n }\n }\n\n // Only calculate Robin-type for elements when required\n if (isOnRobinTypeBoundary) {\n const { gaussPoints, gaussWeights } = FEAData;\n const result = thermalBoundaryConditions.imposeConvectionBoundaryConditionsFront(\n elementIndex,\n meshData.nodesXCoordinates,\n meshData.nodesYCoordinates,\n gaussPoints,\n gaussWeights,\n basisFunctions\n );\n boundaryLocalJacobianMatrix = result.localJacobianMatrix;\n boundaryResidualVector = result.localResidualVector;\n }\n } else if (assembleFront === assembleFrontPropagationFront) {\n // For now, no Robin-type boundary conditions exist for any other solver\n }\n\n // Combine domain and boundary contributions\n for (let localNodeI = 0; localNodeI < FEAData.numNodes; localNodeI++) {\n for (let localNodeJ = 0; localNodeJ < FEAData.numNodes; localNodeJ++) {\n elementData.localJacobianMatrix[localNodeI][localNodeJ] =\n localJacobianMatrix[localNodeI][localNodeJ] + boundaryLocalJacobianMatrix[localNodeI][localNodeJ];\n }\n }\n\n // Assemble local element residual\n for (let localNodeIndex = 0; localNodeIndex < FEAData.numNodes; localNodeIndex++) {\n const globalNodeIndex = ngl[localNodeIndex] - 1;\n frontalData.globalResidualVector[globalNodeIndex] +=\n localResidualVector[localNodeIndex] + boundaryResidualVector[localNodeIndex];\n }\n\n return true;\n}\n\n/**\n * Function to implement the frontal solver algorithm\n * @param {object} meshData - Object containing mesh data\n * @param {object} FEAData - Object containing FEA-related data\n * @param {object} thermalBoundaryConditions - Object containing thermal boundary conditions\n * @param {function} assembleFront - Matrix assembler based on the physical model\n */\nfunction runFrontalAlgorithm(meshData, FEAData, thermalBoundaryConditions, assembleFront) {\n // Allocate local arrays dynamically\n const totalElements = meshData.totalElements;\n const numNodes = meshData.nodesXCoordinates.length;\n const systemSize = Math.max(numNodes, frontalState.globalSolutionVector.length);\n let localDestination = Array(FEAData.numNodes).fill(0);\n let rowDestination = Array(FEAData.numNodes).fill(0);\n let rowHeaders = Array(systemSize).fill(0);\n let pivotRowIndices = Array(systemSize).fill(0);\n let pivotColumnIndices = Array(systemSize).fill(0);\n let modifiedRows = Array(systemSize).fill(0);\n let pivotColumn = Array(systemSize).fill(0);\n let frontMatrix = Array(systemSize)\n .fill()\n .map(() => Array(systemSize).fill(0));\n let rowSwapCount = Array(numNodes).fill(0);\n let columnSwapCount = Array(numNodes).fill(0);\n let lastAppearanceCheck = Array(numNodes).fill(0);\n let pivotColumnGlobalIndex; // Pivot column global index\n\n let frontDataCounter = 1;\n frontalState.writeFlag++;\n let pivotDataIndex = 1;\n let summedRows = 1;\n elementData.currentElementIndex = 0;\n\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n rowSwapCount[nodeIndex] = 0;\n columnSwapCount[nodeIndex] = 0;\n }\n\n if (frontalState.transformationFlag !== 0) {\n // Prefront: find last appearance of each node\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n lastAppearanceCheck[nodeIndex] = 0;\n }\n\n for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) {\n let reverseElementIndex = totalElements - elementIndex - 1;\n for (\n let localNodeIndex = 0;\n localNodeIndex < frontalState.nodesPerElement[reverseElementIndex];\n localNodeIndex++\n ) {\n let globalNodeIndex = frontalData.nodalNumbering[reverseElementIndex][localNodeIndex];\n if (lastAppearanceCheck[globalNodeIndex - 1] === 0) {\n lastAppearanceCheck[globalNodeIndex - 1] = 1;\n frontalData.nodalNumbering[reverseElementIndex][localNodeIndex] =\n -frontalData.nodalNumbering[reverseElementIndex][localNodeIndex];\n }\n }\n }\n }\n\n frontalState.transformationFlag = 0;\n let columnCount = 0;\n let rowCount = 0;\n\n for (let i = 0; i < systemSize; i++) {\n for (let j = 0; j < systemSize; j++) {\n frontMatrix[j][i] = 0;\n }\n }\n\n while (true) {\n // Assemble a new element only while we still have elements\n let assembled = false;\n let numElementNodes = 0;\n let numElementColumns = 0;\n\n if (elementData.currentElementIndex < totalElements) {\n elementData.currentElementIndex++;\n assembled = assembleElementContribution(meshData, FEAData, thermalBoundaryConditions, assembleFront);\n }\n\n if (assembled) {\n const currentElement = elementData.currentElementIndex;\n numElementNodes = frontalState.nodesPerElement[currentElement - 1];\n numElementColumns = frontalState.nodesPerElement[currentElement - 1];\n\n for (let localNodeIndex = 0; localNodeIndex < numElementColumns; localNodeIndex++) {\n let globalNodeIndex = frontalData.nodalNumbering[currentElement - 1][localNodeIndex];\n let columnIndex;\n\n if (columnCount === 0) {\n columnCount++;\n localDestination[localNodeIndex] = columnCount;\n frontStorage.columnHeaders[columnCount - 1] = globalNodeIndex;\n } else {\n for (columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n if (Math.abs(globalNodeIndex) === Math.abs(frontStorage.columnHeaders[columnIndex])) break;\n }\n\n if (columnIndex === columnCount) {\n columnCount++;\n localDestination[localNodeIndex] = columnCount;\n frontStorage.columnHeaders[columnCount - 1] = globalNodeIndex;\n } else {\n localDestination[localNodeIndex] = columnIndex + 1;\n frontStorage.columnHeaders[columnIndex] = globalNodeIndex;\n }\n }\n\n let rowIndex;\n if (rowCount === 0) {\n rowCount++;\n rowDestination[localNodeIndex] = rowCount;\n rowHeaders[rowCount - 1] = globalNodeIndex;\n } else {\n for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n if (Math.abs(globalNodeIndex) === Math.abs(rowHeaders[rowIndex])) break;\n }\n\n if (rowIndex === rowCount) {\n rowCount++;\n rowDestination[localNodeIndex] = rowCount;\n rowHeaders[rowCount - 1] = globalNodeIndex;\n } else {\n rowDestination[localNodeIndex] = rowIndex + 1;\n rowHeaders[rowIndex] = globalNodeIndex;\n }\n }\n }\n\n if (rowCount > systemSize || columnCount > systemSize) {\n errorLog(\"Error: systemSize not large enough\");\n return;\n }\n\n for (let localColumnIndex = 0; localColumnIndex < numElementColumns; localColumnIndex++) {\n let frontColumnIndex = localDestination[localColumnIndex];\n for (let localRowIndex = 0; localRowIndex < numElementNodes; localRowIndex++) {\n let frontRowIndex = rowDestination[localRowIndex];\n frontMatrix[frontRowIndex - 1][frontColumnIndex - 1] +=\n elementData.localJacobianMatrix[localRowIndex][localColumnIndex];\n }\n }\n }\n\n // Pivoting/elimination continues whether or not a new element was assembled\n let availableColumnCount = 0;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n if (frontStorage.columnHeaders[columnIndex] < 0) {\n pivotColumnIndices[availableColumnCount] = columnIndex + 1;\n availableColumnCount++;\n }\n }\n\n let constrainedRowCount = 0;\n let availableRowCount = 0;\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n let globalNodeIndex = rowHeaders[rowIndex];\n if (globalNodeIndex < 0) {\n pivotRowIndices[availableRowCount] = rowIndex + 1;\n availableRowCount++;\n let absoluteNodeIndex = Math.abs(globalNodeIndex);\n if (frontalData.nodeConstraintCode[absoluteNodeIndex - 1] === 1) {\n modifiedRows[constrainedRowCount] = rowIndex + 1;\n constrainedRowCount++;\n frontalData.nodeConstraintCode[absoluteNodeIndex - 1] = 2;\n frontalData.globalResidualVector[absoluteNodeIndex - 1] =\n frontalData.boundaryValues[absoluteNodeIndex - 1];\n }\n }\n }\n\n if (constrainedRowCount > 0) {\n for (let constrainedIndex = 0; constrainedIndex < constrainedRowCount; constrainedIndex++) {\n let rowIndex = modifiedRows[constrainedIndex] - 1;\n let globalNodeIndex = Math.abs(rowHeaders[rowIndex]);\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex][columnIndex] = 0;\n let columnGlobalIndex = Math.abs(frontStorage.columnHeaders[columnIndex]);\n if (columnGlobalIndex === globalNodeIndex) frontMatrix[rowIndex][columnIndex] = 1;\n }\n }\n }\n\n if (availableColumnCount > summedRows || elementData.currentElementIndex < totalElements) {\n if (availableColumnCount === 0) {\n errorLog(\"Error: no more rows fully summed\");\n return;\n }\n\n let pivotRowIndex = pivotRowIndices[0];\n let pivotColumnIndex = pivotColumnIndices[0];\n let pivotValue = frontMatrix[pivotRowIndex - 1][pivotColumnIndex - 1];\n\n if (Math.abs(pivotValue) < 1e-4) {\n pivotValue = 0;\n for (let columnIndex = 0; columnIndex < availableColumnCount; columnIndex++) {\n let testColumnIndex = pivotColumnIndices[columnIndex];\n for (let rowIndex = 0; rowIndex < availableRowCount; rowIndex++) {\n let testRowIndex = pivotRowIndices[rowIndex];\n let testValue = frontMatrix[testRowIndex - 1][testColumnIndex - 1];\n if (Math.abs(testValue) > Math.abs(pivotValue)) {\n pivotValue = testValue;\n pivotColumnIndex = testColumnIndex;\n pivotRowIndex = testRowIndex;\n }\n }\n }\n }\n\n let pivotGlobalRowIndex = Math.abs(rowHeaders[pivotRowIndex - 1]);\n pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[pivotColumnIndex - 1]); // Assign, don't declare\n let permutationHelper =\n pivotGlobalRowIndex +\n pivotColumnGlobalIndex +\n rowSwapCount[pivotGlobalRowIndex - 1] +\n columnSwapCount[pivotColumnGlobalIndex - 1];\n frontalState.determinant =\n (frontalState.determinant * pivotValue * (-1) ** permutationHelper) / Math.abs(pivotValue);\n\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n if (nodeIndex >= pivotGlobalRowIndex) rowSwapCount[nodeIndex]--;\n if (nodeIndex >= pivotColumnGlobalIndex) columnSwapCount[nodeIndex]--;\n }\n\n if (Math.abs(pivotValue) < 1e-10) {\n errorLog(\n `Matrix singular or ill-conditioned, currentElementIndex=${elementData.currentElementIndex}, pivotGlobalRowIndex=${pivotGlobalRowIndex}, pivotColumnGlobalIndex=${pivotColumnGlobalIndex}, pivotValue=${pivotValue}`\n );\n }\n\n if (pivotValue === 0) return;\n\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.pivotRow[columnIndex] = frontMatrix[pivotRowIndex - 1][columnIndex] / pivotValue;\n }\n\n let rightHandSide = frontalData.globalResidualVector[pivotGlobalRowIndex - 1] / pivotValue;\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] = rightHandSide;\n pivotColumn[pivotRowIndex - 1] = pivotValue;\n\n if (pivotRowIndex > 1) {\n for (let rowIndex = 0; rowIndex < pivotRowIndex - 1; rowIndex++) {\n let globalRowIndex = Math.abs(rowHeaders[rowIndex]);\n let eliminationFactor = frontMatrix[rowIndex][pivotColumnIndex - 1];\n pivotColumn[rowIndex] = eliminationFactor;\n if (pivotColumnIndex > 1 && eliminationFactor !== 0) {\n for (let columnIndex = 0; columnIndex < pivotColumnIndex - 1; columnIndex++) {\n frontMatrix[rowIndex][columnIndex] -= eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n if (pivotColumnIndex < columnCount) {\n for (let columnIndex = pivotColumnIndex; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex][columnIndex - 1] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n frontalData.globalResidualVector[globalRowIndex - 1] -= eliminationFactor * rightHandSide;\n }\n }\n\n if (pivotRowIndex < rowCount) {\n for (let rowIndex = pivotRowIndex; rowIndex < rowCount; rowIndex++) {\n let globalRowIndex = Math.abs(rowHeaders[rowIndex]);\n let eliminationFactor = frontMatrix[rowIndex][pivotColumnIndex - 1];\n pivotColumn[rowIndex] = eliminationFactor;\n if (pivotColumnIndex > 1) {\n for (let columnIndex = 0; columnIndex < pivotColumnIndex - 1; columnIndex++) {\n frontMatrix[rowIndex - 1][columnIndex] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n if (pivotColumnIndex < columnCount) {\n for (let columnIndex = pivotColumnIndex; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowIndex - 1][columnIndex - 1] =\n frontMatrix[rowIndex][columnIndex] - eliminationFactor * frontStorage.pivotRow[columnIndex];\n }\n }\n frontalData.globalResidualVector[globalRowIndex - 1] -= eliminationFactor * rightHandSide;\n }\n }\n\n for (let i = 0; i < rowCount; i++) {\n frontStorage.pivotData[pivotDataIndex + i - 1] = pivotColumn[i];\n }\n pivotDataIndex += rowCount;\n\n for (let i = 0; i < rowCount; i++) {\n frontStorage.pivotData[pivotDataIndex + i - 1] = rowHeaders[i];\n }\n pivotDataIndex += rowCount;\n\n frontStorage.pivotData[pivotDataIndex - 1] = pivotRowIndex;\n pivotDataIndex++;\n\n for (let i = 0; i < columnCount; i++) {\n frontStorage.frontValues[frontDataCounter - 1 + i] = frontStorage.pivotRow[i];\n }\n frontDataCounter += columnCount;\n\n for (let i = 0; i < columnCount; i++) {\n frontStorage.frontValues[frontDataCounter - 1 + i] = frontStorage.columnHeaders[i];\n }\n frontDataCounter += columnCount;\n\n frontStorage.frontValues[frontDataCounter - 1] = pivotGlobalRowIndex;\n frontStorage.frontValues[frontDataCounter] = columnCount;\n frontStorage.frontValues[frontDataCounter + 1] = pivotColumnIndex;\n frontStorage.frontValues[frontDataCounter + 2] = pivotValue;\n frontDataCounter += 4;\n\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n frontMatrix[rowIndex][columnCount - 1] = 0;\n }\n\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontMatrix[rowCount - 1][columnIndex] = 0;\n }\n\n columnCount--;\n if (pivotColumnIndex < columnCount + 1) {\n for (let columnIndex = pivotColumnIndex - 1; columnIndex < columnCount; columnIndex++) {\n frontStorage.columnHeaders[columnIndex] = frontStorage.columnHeaders[columnIndex + 1];\n }\n }\n\n rowCount--;\n if (pivotRowIndex < rowCount + 1) {\n for (let rowIndex = pivotRowIndex - 1; rowIndex < rowCount; rowIndex++) {\n rowHeaders[rowIndex] = rowHeaders[rowIndex + 1];\n }\n }\n\n if (rowCount > 1 || elementData.currentElementIndex < totalElements) continue;\n\n pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[0]); // Assign, don't declare\n pivotRowIndex = 1;\n pivotValue = frontMatrix[0][0];\n pivotGlobalRowIndex = Math.abs(rowHeaders[0]);\n pivotColumnIndex = 1;\n permutationHelper =\n pivotGlobalRowIndex +\n pivotColumnGlobalIndex +\n rowSwapCount[pivotGlobalRowIndex - 1] +\n columnSwapCount[pivotColumnGlobalIndex - 1];\n frontalState.determinant =\n (frontalState.determinant * pivotValue * (-1) ** permutationHelper) / Math.abs(pivotValue);\n\n frontStorage.pivotRow[0] = 1;\n if (Math.abs(pivotValue) < 1e-10) {\n errorLog(\n `Matrix singular or ill-conditioned, currentElementIndex=${elementData.currentElementIndex}, pivotGlobalRowIndex=${pivotGlobalRowIndex}, pivotColumnGlobalIndex=${pivotColumnGlobalIndex}, pivotValue=${pivotValue}`\n );\n }\n\n if (pivotValue === 0) return;\n\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] =\n frontalData.globalResidualVector[pivotGlobalRowIndex - 1] / pivotValue;\n frontStorage.frontValues[frontDataCounter - 1] = frontStorage.pivotRow[0];\n frontDataCounter++;\n frontStorage.frontValues[frontDataCounter - 1] = frontStorage.columnHeaders[0];\n frontDataCounter++;\n frontStorage.frontValues[frontDataCounter - 1] = pivotGlobalRowIndex;\n frontStorage.frontValues[frontDataCounter] = columnCount;\n frontStorage.frontValues[frontDataCounter + 1] = pivotColumnIndex;\n frontStorage.frontValues[frontDataCounter + 2] = pivotValue;\n frontDataCounter += 4;\n\n frontStorage.pivotData[pivotDataIndex - 1] = pivotColumn[0];\n pivotDataIndex++;\n frontStorage.pivotData[pivotDataIndex - 1] = rowHeaders[0];\n pivotDataIndex++;\n frontStorage.pivotData[pivotDataIndex - 1] = pivotRowIndex;\n pivotDataIndex++;\n\n frontalState.frontDataIndex = frontDataCounter;\n if (frontalState.writeFlag === 1)\n debugLog(`total ecs transfer in matrix reduction=${frontDataCounter}`);\n\n // Back substitution\n performBackSubstitution(frontDataCounter);\n break;\n }\n }\n}\n\n/**\n * Function to perform back substitution for the frontal solver\n * @param {number} frontDataCounter - Index counter for the element contributions\n */\nfunction performBackSubstitution(frontDataCounter) {\n for (let nodeIndex = 0; nodeIndex < frontalState.totalNodes; nodeIndex++) {\n frontalState.globalSolutionVector[nodeIndex] = frontalData.boundaryValues[nodeIndex];\n }\n\n for (let iterationIndex = 1; iterationIndex <= frontalState.totalNodes; iterationIndex++) {\n frontDataCounter -= 4;\n let pivotGlobalRowIndex = frontStorage.frontValues[frontDataCounter - 1];\n let columnCount = frontStorage.frontValues[frontDataCounter];\n let pivotColumnIndex = frontStorage.frontValues[frontDataCounter + 1];\n let pivotValue = frontStorage.frontValues[frontDataCounter + 2];\n\n if (iterationIndex === 1) {\n frontDataCounter--;\n frontStorage.columnHeaders[0] = frontStorage.frontValues[frontDataCounter - 1];\n frontDataCounter--;\n frontStorage.pivotRow[0] = frontStorage.frontValues[frontDataCounter - 1];\n } else {\n frontDataCounter -= columnCount;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.columnHeaders[columnIndex] =\n frontStorage.frontValues[frontDataCounter - 1 + columnIndex];\n }\n frontDataCounter -= columnCount;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n frontStorage.pivotRow[columnIndex] = frontStorage.frontValues[frontDataCounter - 1 + columnIndex];\n }\n }\n\n let pivotColumnGlobalIndex = Math.abs(frontStorage.columnHeaders[pivotColumnIndex - 1]);\n if (frontalData.nodeConstraintCode[pivotColumnGlobalIndex - 1] > 0) continue;\n\n let accumulatedValue = 0;\n frontStorage.pivotRow[pivotColumnIndex - 1] = 0;\n for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n accumulatedValue -=\n frontStorage.pivotRow[columnIndex] *\n frontalState.globalSolutionVector[Math.abs(frontStorage.columnHeaders[columnIndex]) - 1];\n }\n\n frontalState.globalSolutionVector[pivotColumnGlobalIndex - 1] =\n accumulatedValue + frontalData.globalResidualVector[pivotGlobalRowIndex - 1];\n\n frontalData.nodeConstraintCode[pivotColumnGlobalIndex - 1] = 1;\n }\n\n if (frontalState.writeFlag === 1)\n debugLog(`value of frontDataCounter after backsubstitution=${frontDataCounter}`);\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 { runFrontalSolver } from \"./frontalSolverScript.js\";\nimport { assembleFrontPropagationFront } from \"../solvers/frontPropagationScript.js\";\n\n/**\n * Function to solve a system of non-linear equations using the Newton-Raphson method\n * @param {function} assembleMat - Matrix assembler based on the physical model\n * @param {object} context - Context object containing simulation data and options\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\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 // Check if using frontal solver\n if (context.solverMethod === \"frontal\") {\n const frontalResult = runFrontalSolver(\n assembleFrontPropagationFront,\n context.meshData,\n context.boundaryConditions,\n { solutionVector, eikonalActivationFlag: context.eikonalActivationFlag }\n );\n deltaX = frontalResult.solutionVector;\n } else {\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\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 * @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 { assembleGeneralFormPDEMat, assembleGeneralFormPDEFront } from \"./solvers/generalFormPDEScript.js\";\nimport { assembleHeatConductionMat, assembleHeatConductionFront } from \"./solvers/heatConductionScript.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 this.coefficientFunctions = null; // Add storage for coefficient functions\n basicLog(\"FEAScriptModel instance created\");\n }\n\n /**\n * Sets the solver configuration\n * @param {string} solverConfig - Parameter specifying the type of solver\n * @param {object} [options] - Optional additional configuration\n */\n setSolverConfig(solverConfig, options = {}) {\n this.solverConfig = solverConfig;\n\n // Store coefficient functions if provided\n if (options && options.coefficientFunctions) {\n this.coefficientFunctions = options.coefficientFunctions;\n debugLog(\"Coefficient functions set\");\n }\n\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 /**\n * For consistency across both linear and nonlinear formulations,\n * this project always refers to the assembled right-hand side vector\n * as `residualVector` and the assembled system matrix as `jacobianMatrix`.\n *\n * In linear problems `jacobianMatrix` is equivalent to the\n * classic stiffness/conductivity matrix and `residualVector`\n * corresponds to the traditional load (RHS) vector.\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 === \"heatConductionScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n\n // Check if using frontal solver\n if (this.solverMethod === \"frontal\") {\n const frontalResult = runFrontalSolver(\n assembleHeatConductionFront,\n meshData,\n this.boundaryConditions\n );\n solutionVector = frontalResult.solutionVector;\n } else {\n // Use regular linear solver methods\n ({ jacobianMatrix, residualVector } = assembleHeatConductionMat(meshData, this.boundaryConditions));\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 } else if (this.solverConfig === \"generalFormPDEScript\") {\n basicLog(`Using solver: ${this.solverConfig}`);\n // Check if using frontal solver\n if (this.solverMethod === \"frontal\") {\n errorLog(\n \"Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.\"\n );\n } else {\n // Use regular linear solver methods\n ({ jacobianMatrix, residualVector } = assembleGeneralFormPDEMat(\n meshData,\n this.boundaryConditions,\n this.coefficientFunctions\n ));\n\n const linearSystemResult = solveLinearSystem(this.solverMethod, jacobianMatrix, residualVector);\n solutionVector = linearSystemResult.solutionVector;\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 { initializeFEA, performIsoparametricMapping1D } from \"../mesh/meshUtilsScript.js\";\nimport { GenericBoundaryConditions } from \"./genericBoundaryConditionsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to assemble the Jacobian matrix and residuals vector for the general form PDE model\n * @param {object} meshData - Object containing prepared mesh data\n * @param {object} boundaryConditions - Object containing boundary conditions\n * @param {object} coefficientFunctions - Functions A(x), B(x), C(x), D(x) for the PDE\n * @returns {object} An object containing:\n * - jacobianMatrix: The assembled Jacobian matrix\n * - residualVector: The assembled residual vector\n */\nexport function assembleGeneralFormPDEMat(meshData, boundaryConditions, coefficientFunctions) {\n basicLog(\"Starting general form PDE 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 // Extract coefficient functions\n const { A, B, C, D } = coefficientFunctions;\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 if (meshDimension === \"1D\") {\n // 1D general form PDE\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 // Convert to 0-based indexing\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n // Loop over Gauss points\n for (let gaussPointIndex = 0; gaussPointIndex < gaussPoints.length; gaussPointIndex++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < numNodes; i++) {\n xCoord += nodesXCoordinates[localToGlobalMap[i]] * basisFunction[i];\n }\n\n // Evaluate coefficient functions at this physical coordinate\n const a = A(xCoord);\n const b = B(xCoord);\n const c = C(xCoord);\n const d = D(xCoord);\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n const globalNodeIndex1 = localToGlobalMap[localNodeIndex1];\n\n // Source term contribution to residual vector\n residualVector[globalNodeIndex1] -=\n gaussWeights[gaussPointIndex] * detJacobian * d * basisFunction[localNodeIndex1];\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n const globalNodeIndex2 = localToGlobalMap[localNodeIndex2];\n\n // Diffusion term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n a *\n basisFunctionDerivX[localNodeIndex1] *\n basisFunctionDerivX[localNodeIndex2];\n\n // Advection term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n b *\n basisFunctionDerivX[localNodeIndex2] *\n basisFunction[localNodeIndex1];\n\n // Reaction term\n jacobianMatrix[globalNodeIndex1][globalNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n c *\n basisFunction[localNodeIndex1] *\n basisFunction[localNodeIndex2];\n }\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n errorLog(\"2D general form PDE is not yet supported in assembleGeneralFormPDEMat.\");\n // 2D general form PDE - empty for now\n }\n\n // Apply boundary conditions\n const genericBoundaryConditions = new GenericBoundaryConditions(\n boundaryConditions,\n boundaryElements,\n nop,\n meshDimension,\n elementOrder\n );\n\n // Apply Dirichlet boundary conditions only\n genericBoundaryConditions.imposeDirichletBoundaryConditions(residualVector, jacobianMatrix);\n\n basicLog(\"General form PDE matrix assembly completed\");\n\n return {\n jacobianMatrix,\n residualVector,\n };\n}\n\n/**\n * Function to assemble the frontal solver matrix for the general form PDE model\n * @param {object} data - Object containing element data for the frontal solver\n * @returns {object} An object containing local Jacobian matrix and residual vector\n */\nexport function assembleGeneralFormPDEFront({\n elementIndex,\n nop,\n meshData,\n basisFunctions,\n FEAData,\n coefficientFunctions,\n}) {\n // Extract numerical integration parameters and mesh coordinates\n const { gaussPoints, gaussWeights, numNodes } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n const { A, B, C, D } = coefficientFunctions;\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(numNodes)\n .fill()\n .map(() => Array(numNodes).fill(0));\n const localResidualVector = Array(numNodes).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(numNodes);\n const localToGlobalMap = Array(numNodes);\n for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) {\n ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]);\n localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1;\n }\n\n if (meshDimension === \"1D\") {\n // 1D general form PDE\n\n // Loop over Gauss points\n for (let gaussPointIndex = 0; gaussPointIndex < gaussPoints.length; gaussPointIndex++) {\n // Get basis functions for the current Gauss point\n const { basisFunction, basisFunctionDerivKsi } = basisFunctions.getBasisFunctions(\n gaussPoints[gaussPointIndex]\n );\n\n // Perform isoparametric mapping\n const { detJacobian, basisFunctionDerivX } = performIsoparametricMapping1D({\n basisFunction,\n basisFunctionDerivKsi,\n nodesXCoordinates,\n localToGlobalMap,\n numNodes,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < numNodes; i++) {\n xCoord += nodesXCoordinates[localToGlobalMap[i]] * basisFunction[i];\n }\n\n // Evaluate coefficient functions at this physical coordinate\n const a = A(xCoord);\n const b = B(xCoord);\n const c = C(xCoord);\n const d = D(xCoord);\n\n // Computation of local Jacobian matrix and residual vector\n for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) {\n // Source term contribution to local residual vector\n localResidualVector[localNodeIndex1] -=\n gaussWeights[gaussPointIndex] * detJacobian * d * basisFunction[localNodeIndex1];\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) {\n // Diffusion term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] +=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n a *\n basisFunctionDerivX[localNodeIndex1] *\n basisFunctionDerivX[localNodeIndex2];\n\n // Advection term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n b *\n basisFunctionDerivX[localNodeIndex2] *\n basisFunction[localNodeIndex1];\n\n // Reaction term\n localJacobianMatrix[localNodeIndex1][localNodeIndex2] -=\n gaussWeights[gaussPointIndex] *\n detJacobian *\n c *\n basisFunction[localNodeIndex1] *\n basisFunction[localNodeIndex2];\n }\n }\n }\n } else if (meshDimension === \"2D\") {\n errorLog(\"2D general form PDE is not yet supported in assembleGeneralFormPDEFront.\");\n // 2D general form PDE - empty for now\n }\n\n return {\n localJacobianMatrix,\n localResidualVector,\n ngl,\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\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// | ____| ____| /\\ / ____| (_) | | //\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 } from \"./utilities/loggingScript.js\";\nexport { plotSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const printVersion = \"0.1.3\";"],"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","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","nodesXCoordinates","totalNodesX","deltaX","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","meshData","totalNodes","colIndex","basisFunctions","gaussPointsAndWeights","localToGlobalMap","numNodes","performIsoparametricMapping1D","params","xCoordinates","ksiDerivX","localNodeIndex","detJacobian","basisFunctionDerivX","performIsoparametricMapping2D","yCoordinates","etaDerivX","ksiDerivY","etaDerivY","basisFunctionDerivY","ThermalBoundaryConditions","boundaryConditions","imposeConstantTempBoundaryConditions","Object","keys","boundaryKey","tempValue","globalNodeIndex","imposeConstantTempBoundaryConditionsFront","nodeConstraintCode","boundaryValues","imposeConvectionBoundaryConditions","convectionHeatTranfCoeff","convectionExtTemp","key","boundaryCondition","convectionCoeff","extTemp","gaussPoint1","gaussPoint2","firstNodeIndex","lastNodeIndex","nodeIncrement","basisFunctionsAndDerivatives","tangentVectorLength","localNodeIndex2","globalNodeIndex2","gaussPointIndex","imposeConvectionBoundaryConditionsFront","localJacobianMatrix","map","localResidualVector","boundaryElement","find","_","assembleHeatConductionFront","FEAData","ngl","gaussPointIndex1","localNodeIndex1","gaussPointIndex2","globalIndex","GenericBoundaryConditions","imposeDirichletBoundaryConditions","value","imposeConstantValueBoundaryConditionsFront","assembleFrontPropagationMat","eikonalActivationFlag","eikonalViscousTerm","totalElements","mappingResult","solutionDerivX","solutionDerivY","localToGlobalMap1","localToGlobalMap2","assembleFrontPropagationFront","frontalData","frontalState","elementData","currentElementIndex","frontStorage","runFrontalSolver","assembleFront","numElements","globalResidualVector","topologyData","lateralData","writeFlag","transformationFlag","nodesPerElement","determinant","systemSize","globalSolutionVector","frontDataIndex","frontSize","frontWidthEstimate","ceil","estimateFrontSize","frontValues","columnHeaders","pivotRow","pivotData","initializeFrontalArrays","dirichletBoundaryConditionsHandler","currentSolutionVector","thermalBoundaryConditions","pivotColumnGlobalIndex","localDestination","rowDestination","rowHeaders","pivotRowIndices","pivotColumnIndices","modifiedRows","pivotColumn","frontMatrix","rowSwapCount","columnSwapCount","lastAppearanceCheck","frontDataCounter","pivotDataIndex","summedRows","reverseElementIndex","columnCount","rowCount","assembled","numElementNodes","numElementColumns","assembleElementContribution","currentElement","columnIndex","rowIndex","localColumnIndex","frontColumnIndex","localRowIndex","availableColumnCount","constrainedRowCount","availableRowCount","absoluteNodeIndex","constrainedIndex","pivotRowIndex","pivotColumnIndex","pivotValue","testColumnIndex","testRowIndex","testValue","pivotGlobalRowIndex","permutationHelper","rightHandSide","globalRowIndex","eliminationFactor","performBackSubstitution","runFrontalAlgorithm","toExponential","finalNodesX","finalNodesY","slice","nodesCoordinates","boundaryLocalJacobianMatrix","boundaryResidualVector","isOnRobinTypeBoundary","some","result","localNodeI","localNodeJ","iterationIndex","accumulatedValue","newtonRaphson","assembleMat","context","errorNorm","initialSolution","Number","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","meshConfig","coefficientFunctions","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","mesh","nodesCoordinatesAndNumbering","prepareMesh","assembleHeatConductionMat","eikonalExteralIterations","newtonRaphsonResult","A","B","C","D","xCoord","a","b","d","globalNodeIndex1","assembleGeneralFormPDEMat","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","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","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","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"],"mappings":"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"} \ No newline at end of file diff --git a/examples/generalFormPDEScript/advectionDiffusion1D/README.md b/examples/generalFormPDEScript/advectionDiffusion1D/README.md index 3b54993..a60be0e 100644 --- a/examples/generalFormPDEScript/advectionDiffusion1D/README.md +++ b/examples/generalFormPDEScript/advectionDiffusion1D/README.md @@ -1,4 +1,4 @@ - +FEAScript General Form PDE Logo ## Advection-Diffusion with Gaussian Source diff --git a/package.json b/package.json index 8e54bf2..2dde7b1 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "scripts": { "build": "rollup -c", "prepublishOnly": "npm run build", - "test": "echo \"No tests configured\" && exit 0" + "test": "for file in $(find examples -name '*.js' -type f | sort); do echo 'Running' \"$file\"; if node \"$file\" > /dev/null 2>&1; then echo 'Success'; else echo 'Failed'; fi; done" }, "repository": { "type": "git", @@ -44,6 +44,14 @@ { "name": "Felipe Ferrari", "url": "https://github.com/ferrari212" + }, + { + "name": "Akhilesh Tiwari", + "url": "https://github.com/silky-x0" + }, + { + "name": "Priyank Bansal", + "url": "https://github.com/Stu-ops" } ], "license": "MIT",