diff --git a/dist/feascript.cjs.js b/dist/feascript.cjs.js index 361c947..38d351d 100644 --- a/dist/feascript.cjs.js +++ b/dist/feascript.cjs.js @@ -4,5 +4,5 @@ function e(e){let t=0;for(let n=0;n"object"==typeof e&&null!==e||"function"==typeof e,u=new Map([["proxy",{canHandle:e=>c(e)&&e[i],serialize(e){const{port1:t,port2:n}=new MessageChannel;return m(e,t),[n,[n]]},deserialize:e=>(e.start(),f(e))}],["throw",{canHandle:e=>c(e)&&d 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 m(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:r,type:a,path:c}=Object.assign({path:[]},s.data),u=(s.data.argumentList||[]).map($);let f;try{const t=c.slice(0,-1).reduce(((e,t)=>e[t]),e),n=c.reduce(((e,t)=>e[t]),e);switch(a){case"GET":f=n;break;case"SET":t[c.slice(-1)[0]]=$(s.data.value),f=!0;break;case"APPLY":f=n.apply(t,u);break;case"CONSTRUCT":f=function(e){return Object.assign(e,{[i]:!0})}(new n(...u));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;m(e,n),f=function(e,t){return C.set(e,t),e}(t,[t])}break;case"RELEASE":f=void 0;break;default:return}}catch(e){f={value:e,[d]:0}}Promise.resolve(f).catch((e=>({value:e,[d]:0}))).then((n=>{const[s,i]=M(n);t.postMessage(Object.assign(Object.assign({},s),{id:r}),i),"RELEASE"===a&&(t.removeEventListener("message",o),h(t),l in e&&"function"==typeof e[l]&&e[l]())})).catch((e=>{const[n,o]=M({value:new TypeError("Unserializable return value"),[d]:0});t.postMessage(Object.assign(Object.assign({},n),{id:r}),o)}))})),t.start&&t.start()}function h(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function f(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)}})),E(e,n,[],t)}function p(e){if(e)throw new Error("Proxy has been released and is not useable")}function b(e){return D(e,new Map,{type:"RELEASE"}).then((()=>{h(e)}))}const g=new WeakMap,y="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(g.get(e)||0)-1;g.set(e,t),0===t&&b(e)}));function E(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(p(s),r===a)return()=>{!function(e){y&&y.unregister(e)}(i),b(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=D(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then($);return o.then.bind(o)}return E(e,t,[...n,r])},set(o,i,r){p(s);const[a,l]=M(r);return D(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then($)},apply(o,i,a){p(s);const l=n[n.length-1];if(l===r)return D(e,t,{type:"ENDPOINT"}).then($);if("bind"===l)return E(e,t,n.slice(0,-1));const[d,c]=v(a);return D(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:d},c).then($)},construct(o,i){p(s);const[r,a]=v(i);return D(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then($)}});return function(e,t){const n=(g.get(t)||0)+1;g.set(t,n),y&&y.register(e,t,e)}(i,e),i}function v(e){const t=e.map(M);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const C=new WeakMap;function M(e){for(const[t,n]of u)if(n.canHandle(e)){const[o,s]=n.serialize(e);return[{type:"HANDLER",name:t,value:o},s]}return[{type:"RAW",value:e},C.get(e)||[]]}function $(e){switch(e.type){case"HANDLER":return u.get(e.name).deserialize(e.value);case"RAW":return e.value}}function D(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)}))}function F(e,t,i,r={}){const{maxIterations:a=1e4,tolerance:l=1e-4}=r;let d=[],c=!0,u=0;if(o(`Solving system using ${e}...`),console.time("systemSolving"),"lusolve"===e){const e=math.sparse(t),n=math.slu(e,1,1);let o=math.lusolve(n,i);d=math.squeeze(o).valueOf()}else if("jacobi"===e){const e=function(e,t,n,o={}){const{maxIterations:s,tolerance:i}=o,r=e.length;let a=[...n],l=new Array(r);for(let n=0;n{}))),m.worker.terminate()),{solutionVector:p,converged:b,iterations:u}}class A{constructor({meshDimension:e,elementOrder:t}){this.meshDimension=e,this.elementOrder=t}getBasisFunctions(e,t=null){let n=[],o=[],i=[];if("1D"===this.meshDimension)"linear"===this.elementOrder?(n[0]=1-e,n[1]=e,o[0]=-1,o[1]=1):"quadratic"===this.elementOrder&&(n[0]=1-3*e+2*e**2,n[1]=4*e-4*e**2,n[2]=2*e**2-e,o[0]=4*e-3,o[1]=4-8*e,o[2]=4*e-1);else if("2D"===this.meshDimension){if(null===t)return void s("Eta coordinate is required for 2D elements");if("linear"===this.elementOrder){function r(e){return 1-e}n[0]=r(e)*r(t),n[1]=r(e)*t,n[2]=e*r(t),n[3]=e*t,o[0]=-1*r(t),o[1]=-1*t,o[2]=1*r(t),o[3]=1*t,i[0]=-1*r(e),i[1]=1*r(e),i[2]=-1*e,i[3]=1*e}else if("quadratic"===this.elementOrder){function a(e){return 2*e**2-3*e+1}function l(e){return-4*e**2+4*e}function d(e){return 2*e**2-e}function c(e){return 4*e-3}function u(e){return-8*e+4}function m(e){return 4*e-1}n[0]=a(e)*a(t),n[1]=a(e)*l(t),n[2]=a(e)*d(t),n[3]=l(e)*a(t),n[4]=l(e)*l(t),n[5]=l(e)*d(t),n[6]=d(e)*a(t),n[7]=d(e)*l(t),n[8]=d(e)*d(t),o[0]=c(e)*a(t),o[1]=c(e)*l(t),o[2]=c(e)*d(t),o[3]=u(e)*a(t),o[4]=u(e)*l(t),o[5]=u(e)*d(t),o[6]=m(e)*a(t),o[7]=m(e)*l(t),o[8]=m(e)*d(t),i[0]=a(e)*c(t),i[1]=a(e)*u(t),i[2]=a(e)*m(t),i[3]=l(e)*c(t),i[4]=l(e)*u(t),i[5]=l(e)*m(t),i[6]=d(e)*c(t),i[7]=d(e)*u(t),i[8]=d(e)*m(t)}}return{basisFunction:n,basisFunctionDerivKsi:o,basisFunctionDerivEta:i}}}class w{constructor({numElementsX:e=null,maxX:t=null,numElementsY:n=null,maxY:s=null,meshDimension:i=null,elementOrder:r="linear",parsedMesh:a=null}){this.numElementsX=e,this.numElementsY=n,this.maxX=t,this.maxY=s,this.meshDimension=i,this.elementOrder=r,this.parsedMesh=a,this.boundaryElementsProcessed=!1,this.parsedMesh&&(o("Using pre-parsed mesh from gmshReader data for mesh generation."),this.parseMeshFromGmsh())}parseMeshFromGmsh(){if(this.parsedMesh.nodalNumbering||s("No valid nodal numbering found in the parsed mesh."),"object"==typeof this.parsedMesh.nodalNumbering&&!Array.isArray(this.parsedMesh.nodalNumbering)){const e=this.parsedMesh.nodalNumbering.quadElements||[];if(this.parsedMesh.nodalNumbering.triangleElements,n("Initial parsed mesh nodal numbering from GMSH format: "+JSON.stringify(this.parsedMesh.nodalNumbering)),this.parsedMesh.elementTypes[3]||this.parsedMesh.elementTypes[10]){const t=[];for(let n=0;n0&&void 0===this.parsedMesh.boundaryElements[0]){const e=[];for(let t=1;t{if(1===e.dimension){const t=this.parsedMesh.boundaryNodePairs[e.tag]||[];t.length>0&&(this.parsedMesh.boundaryElements[e.tag]||(this.parsedMesh.boundaryElements[e.tag]=[]),t.forEach((t=>{const o=t[0],i=t[1];n(`Processing boundary node pair: [${o}, ${i}] for boundary ${e.tag} (${e.name||"unnamed"})`);let r=!1;for(let t=0;t0&&void 0===this.parsedMesh.boundaryElements[0])){const e=[];for(let t=1;t{if("constantTemp"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant temperature of ${s} K (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantTemp"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant temperature of ${s} K (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantTemp"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant temperature of ${s} K (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=1,t[r]=s}))}else if("quadratic"===this.elementOrder){({0:[0],2:[2]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=1,t[r]=s}))}}))}})):"2D"===this.meshDimension&&Object.keys(this.boundaryConditions).forEach((o=>{if("constantTemp"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant temperature of ${s} K (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=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[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=1,t[r]=s}))}}))}}))}imposeConvectionBoundaryConditions(e,t,o,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((o=>{if("convection"===this.boundaryConditions[o][0]){const s=l[o],i=d[o];n(`Boundary ${o}: Applying convection with heat transfer coefficient h=${s} W/(m²·K) and external temperature T∞=${i} K`),this.boundaryElements[o].forEach((([o,r])=>{let a;"linear"===this.elementOrder?a=0===r?0:1:"quadratic"===this.elementOrder&&(a=0===r?0:2);const l=this.nop[o][a]-1;n(` - Applied convection boundary condition to node ${l+1} (element ${o+1}, local node ${a+1})`),e[l]+=-s*i,t[l][l]+=s}))}})):"2D"===this.meshDimension&&Object.keys(this.boundaryConditions).forEach((c=>{if("convection"===this.boundaryConditions[c][0]){const u=l[c],m=d[c];n(`Boundary ${c}: Applying convection with heat transfer coefficient h=${u} W/(m²·K) and external temperature T∞=${m} K`),this.boundaryElements[c].forEach((([l,d])=>{if("linear"===this.elementOrder){let c,h,f,p,b;0===d?(c=o[0],h=0,f=0,p=3,b=2):1===d?(c=0,h=o[0],f=0,p=2,b=1):2===d?(c=o[0],h=1,f=1,p=4,b=2):3===d&&(c=1,h=o[0],f=2,p=4,b=1);let g=a.getBasisFunctions(c,h),y=g.basisFunction,E=g.basisFunctionDerivKsi,v=g.basisFunctionDerivEta,C=0,M=0,$=0,D=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,c=Array(d).fill().map((()=>Array(d).fill(0))),u=Array(d).fill(0);for(const m in this.boundaryElements)if("convection"===this.boundaryConditions[m]?.[0]){const h=a[m],f=l[m];n(`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),n(` - Applied convection boundary condition to node ${t+1} (element ${e+1}, local node ${t+1})`),u[t]+=-h*f,c[t][t]+=h}else if("2D"===this.meshDimension)if("linear"===this.elementOrder){let n,l,m,p,b;0===a?(n=s[0],l=0,m=0,p=3,b=2):1===a?(n=0,l=s[0],m=0,p=2,b=1):2===a?(n=s[0],l=1,m=1,p=4,b=2):3===a&&(n=1,l=s[0],m=2,p=4,b=1);const g=r.getBasisFunctions(n,l),y=g.basisFunction,E=g.basisFunctionDerivKsi,v=g.basisFunctionDerivEta;let C,M=0,$=0,D=0,F=0;for(let n=0;nArray(a).fill(0))),m=Array(a).fill(0),h=Array(a),f=Array(a);for(let n=0;ne-1)),{detJacobian:f,basisFunctionDerivX:p,basisFunctionDerivY:b}=T({basisFunction:n,basisFunctionDerivKsi:s,basisFunctionDerivEta:c,nodesXCoordinates:l,nodesYCoordinates:d,localToGlobalMap:m,numNodes:a});for(let n=0;n{if("constantValue"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant value of ${s} (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantValue"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant value of ${s} (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantValue"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant value of ${s} (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=1,t[r]=s}))}else if("quadratic"===this.elementOrder){({0:[0],2:[2]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=1,t[r]=s}))}}))}})):"2D"===this.meshDimension&&Object.keys(this.boundaryConditions).forEach((o=>{if("constantValue"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant value of ${s} (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=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[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=1,t[r]=s}))}}))}}))}}function B(e,t,s,i){o("Starting front propagation matrix assembly...");let r=1-i+.01;n(`eikonalViscousTerm: ${r}`),n(`eikonalActivationFlag: ${i}`);const{nodesXCoordinates:a,nodesYCoordinates:l,nop:d,boundaryElements:c,totalElements:u,meshDimension:m,elementOrder:h}=e,f=V(e),{residualVector:p,jacobianMatrix:b,localToGlobalMap:g,basisFunctions:y,gaussPoints:E,gaussWeights:v,numNodes:C}=f;for(let e=0;eArray(d).fill(0))),p=Array(d).fill(0),b=Array(d),g=Array(d);for(let n=0;nArray(e).fill(0))),q.nodeConstraintCode=Array(e).fill(0),q.boundaryValues=Array(e).fill(0),q.globalResidualVector=Array(e).fill(0),q.solutionVector=Array(e).fill(0),q.topologyData=Array(t).fill(0),q.lateralData=Array(t).fill(0),W.writeFlag=0,W.totalNodes=e,W.transformationFlag=0,W.nodesPerElement=Array(t).fill(0),W.determinant=1;const n=Math.max(e,2e3);W.globalSolutionVector=Array(n).fill(0),W.frontDataIndex=0,G.localJacobianMatrix=Array(e).fill().map((()=>Array(e).fill(0))),G.currentElementIndex=0;const o=function(e,t){const n=Math.max(Math.ceil(Math.sqrt(t))*e,2*e);return n*t}(e,t);K.frontValues=Array(o).fill(0),K.columnHeaders=Array(n).fill(0),K.pivotRow=Array(n).fill(0),K.pivotData=Array(o).fill(0)}(a.numNodes,d),o("Solving system using frontal..."),console.time("systemSolving"),J=new A({meshDimension:t.meshDimension,elementOrder:t.elementOrder});for(let e=0;eArray(l).fill(0))),y=Array(a).fill(0),E=Array(a).fill(0),v=Array(a).fill(0),C=1;W.writeFlag++;let M=1,$=1;G.currentElementIndex=0;for(let e=0;el||D>l)return void s("Error: systemSize not large enough");for(let e=0;e0)for(let e=0;e$||G.currentElementIndexMath.abs(o)&&(o=r,t=s,e=i)}}}let i=Math.abs(m[e-1]);d=Math.abs(K.columnHeaders[t-1]);let a=i+d+y[i-1]+E[d-1];W.determinant=W.determinant*o*(-1)**a/Math.abs(o);for(let e=0;e=i&&y[e]--,e>=d&&E[e]--;if(Math.abs(o)<1e-10&&s(`Matrix singular or ill-conditioned, currentElementIndex=${G.currentElementIndex}, pivotGlobalRowIndex=${i}, pivotColumnGlobalIndex=${d}, pivotValue=${o}`),0===o)return;for(let t=0;t1)for(let n=0;n1&&0!==o)for(let e=0;e1)for(let e=0;e1||G.currentElementIndex=e.totalElements)return s(`Skipping out-of-range elementIndex=${i} (totalElements=${e.totalElements})`),!1;const{localJacobianMatrix:r,localResidualVector:a,ngl:l}=o({elementIndex:i,nop:q.nodalNumbering,meshData:e,basisFunctions:J,FEAData:t,solutionVector:W.currentSolutionVector,eikonalActivationFlag:W.eikonalActivationFlag});let d=Array(t.numNodes).fill().map((()=>Array(t.numNodes).fill(0))),c=Array(t.numNodes).fill(0);if(o===P){let o=!1;for(const t in e.boundaryElements)if("convection"===n.boundaryConditions[t]?.[0]&&e.boundaryElements[t].some((([e,t])=>e===i))){o=!0;break}if(o){const{gaussPoints:o,gaussWeights:s}=t,r=n.imposeConvectionBoundaryConditionsFront(i,e.nodesXCoordinates,e.nodesYCoordinates,o,s,J);d=r.localJacobianMatrix,c=r.localResidualVector}}for(let e=0;e0)continue;let r=0;K.pivotRow[s-1]=0;for(let e=0;e100){s(`Solution not converged. Error norm: ${i}`);break}a++}return{solutionVector:d,converged:r,iterations:a,jacobianMatrix:c,residualVector:u}}exports.FEAScriptModel=class{constructor(){var e;this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",this.coefficientFunctions=null,e="FEAScript is provided “as is” without any warranty. The authors are not responsible for any damages or losses that may result from using the software. See the license for more details: https://github.com/FEAScript/FEAScript-core/blob/main/LICENSE",console.log("%c[WARN] "+e,"color: #FF9800; font-weight: bold;"),o("FEAScriptModel instance created")}setSolverConfig(e,t={}){this.solverConfig=e,t?.coefficientFunctions&&(this.coefficientFunctions=t.coefficientFunctions,n("Coefficient functions set")),void 0!==t?.maxIterations&&(this.maxIterations=t.maxIterations),void 0!==t?.tolerance&&(this.tolerance=t.tolerance),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(e={}){this.solverConfig&&this.meshConfig&&this.boundaryConditions||s("Solver config, mesh config, and boundary conditions must be set before solving.");let t=[],n=[],i=[],r=[];o("Preparing mesh...");const a=X(this.meshConfig);o("Mesh preparation completed");const l={nodesXCoordinates:a.nodesXCoordinates,nodesYCoordinates:a.nodesYCoordinates};if(o("Beginning solving process..."),console.time("totalSolvingTime"),o(`Using solver: ${this.solverConfig}`),"heatConductionScript"===this.solverConfig)if("frontal"===this.solverMethod){i=H(P,a,this.boundaryConditions).solutionVector}else{({jacobianMatrix:t,residualVector:n}=R(a,this.boundaryConditions));i=F(this.solverMethod,t,n,{maxIterations:e.maxIterations??this.maxIterations,tolerance:e.tolerance??this.tolerance}).solutionVector}else if("frontPropagationScript"===this.solverConfig){let o=0;const s=5,l={meshData:a,boundaryConditions:this.boundaryConditions,eikonalActivationFlag:o,solverMethod:this.solverMethod,initialSolution:r,maxIterations:e.maxIterations??this.maxIterations,tolerance:e.tolerance??this.tolerance};for(;o<=1;){l.eikonalActivationFlag=o,i.length>0&&(l.initialSolution=[...i]);const e=_(B,l);t=e.jacobianMatrix,n=e.residualVector,i=e.solutionVector,o+=1/s}}else if("generalFormPDEScript"===this.solverConfig)if("frontal"===this.solverMethod)s("Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.");else{({jacobianMatrix:t,residualVector:n}=function(e,t,n){o("Starting general form PDE matrix assembly...");const{nodesXCoordinates:i,nodesYCoordinates:r,nop:a,boundaryElements:l,totalElements:d,meshDimension:c,elementOrder:u}=e,{A:m,B:h,C:f,D:p}=n,b=V(e),{residualVector:g,jacobianMatrix:y,localToGlobalMap:E,basisFunctions:v,gaussPoints:C,gaussWeights:M,numNodes:$}=b;if("1D"===c)for(let e=0;e{console.error("FEAScriptWorker: Worker error:",e)};const e=f(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},c=0,u=[],m=0,h=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},b=0,g={};for(;i""!==e));if("meshFormat"===s)t.gmshV=parseFloat(n[0]),t.ascii="0"===n[1],t.fltBytes=n[2];else if("physicalNames"===s){if(n.length>=3){if(!/^\d+$/.test(n[0])){i++;continue}const e=parseInt(n[0],10),o=parseInt(n[1],10);let s=n.slice(2).join(" ");s=s.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:o,dimension:e,name:s})}}else if("nodes"===s){if(0===r){r=parseInt(n[0],10),a=parseInt(n[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;g[n]||(g[n]=[]),g[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);b++,b===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=g[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),n(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t},exports.logSystem=function(e){"basic"!==e&&"debug"!==e?(console.log("%c[WARN] Invalid log level: "+e+". Using basic instead.","color: #FFC107; font-weight: bold;"),t="basic"):(t=e,o(`Log level set to: ${e}`))},exports.plotSolution=function(e,t,n,o,s,i){const{nodesXCoordinates:r,nodesYCoordinates:a}=t;if("1D"===o&&"line"===s){let t;t=e.length>0&&Array.isArray(e[0])?e.map((e=>e[0])):e,Array.from(r);let o={x:r,y:t,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},s=Math.min(window.innerWidth,700),a={title:`line plot - ${n}`,width:Math.min(s,600),height:350,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:50,r:50,t:50,b:50}};Plotly.newPlot(i,[o],a,{responsive:!0})}else if("2D"===o&&"contour"===s){let t;t=Array.isArray(e[0])?e.map((e=>e[0])):e;let o=Math.min(window.innerWidth,700),l=Math.max(...r),d=Math.max(...a)/l,c=Math.min(o,600),u={title:`${s} plot - ${n}`,width:c,height:c*d,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"},m={x:r,y:a,z:t,type:"contour",line:{smoothing:.85},contours:{coloring:"heatmap",showlabels:!1},colorbar:{title:"Solution"},name:"Solution Field"};Plotly.newPlot(i,[m],u,{responsive:!0})}},exports.printVersion="0.1.4"; +const i=Symbol("Comlink.proxy"),r=Symbol("Comlink.endpoint"),a=Symbol("Comlink.releaseProxy"),l=Symbol("Comlink.finalizer"),d=Symbol("Comlink.thrown"),c=e=>"object"==typeof e&&null!==e||"function"==typeof e,u=new Map([["proxy",{canHandle:e=>c(e)&&e[i],serialize(e){const{port1:t,port2:n}=new MessageChannel;return m(e,t),[n,[n]]},deserialize:e=>(e.start(),f(e))}],["throw",{canHandle:e=>c(e)&&d 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 m(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:r,type:a,path:c}=Object.assign({path:[]},s.data),u=(s.data.argumentList||[]).map(D);let f;try{const t=c.slice(0,-1).reduce(((e,t)=>e[t]),e),n=c.reduce(((e,t)=>e[t]),e);switch(a){case"GET":f=n;break;case"SET":t[c.slice(-1)[0]]=D(s.data.value),f=!0;break;case"APPLY":f=n.apply(t,u);break;case"CONSTRUCT":f=function(e){return Object.assign(e,{[i]:!0})}(new n(...u));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;m(e,n),f=function(e,t){return C.set(e,t),e}(t,[t])}break;case"RELEASE":f=void 0;break;default:return}}catch(e){f={value:e,[d]:0}}Promise.resolve(f).catch((e=>({value:e,[d]:0}))).then((n=>{const[s,i]=M(n);t.postMessage(Object.assign(Object.assign({},s),{id:r}),i),"RELEASE"===a&&(t.removeEventListener("message",o),h(t),l in e&&"function"==typeof e[l]&&e[l]())})).catch((e=>{const[n,o]=M({value:new TypeError("Unserializable return value"),[d]:0});t.postMessage(Object.assign(Object.assign({},n),{id:r}),o)}))})),t.start&&t.start()}function h(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function f(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)}})),E(e,n,[],t)}function p(e){if(e)throw new Error("Proxy has been released and is not useable")}function b(e){return $(e,new Map,{type:"RELEASE"}).then((()=>{h(e)}))}const g=new WeakMap,y="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(g.get(e)||0)-1;g.set(e,t),0===t&&b(e)}));function E(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(p(s),r===a)return()=>{!function(e){y&&y.unregister(e)}(i),b(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=$(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(D);return o.then.bind(o)}return E(e,t,[...n,r])},set(o,i,r){p(s);const[a,l]=M(r);return $(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(D)},apply(o,i,a){p(s);const l=n[n.length-1];if(l===r)return $(e,t,{type:"ENDPOINT"}).then(D);if("bind"===l)return E(e,t,n.slice(0,-1));const[d,c]=v(a);return $(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:d},c).then(D)},construct(o,i){p(s);const[r,a]=v(i);return $(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(D)}});return function(e,t){const n=(g.get(t)||0)+1;g.set(t,n),y&&y.register(e,t,e)}(i,e),i}function v(e){const t=e.map(M);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const C=new WeakMap;function M(e){for(const[t,n]of u)if(n.canHandle(e)){const[o,s]=n.serialize(e);return[{type:"HANDLER",name:t,value:o},s]}return[{type:"RAW",value:e},C.get(e)||[]]}function D(e){switch(e.type){case"HANDLER":return u.get(e.name).deserialize(e.value);case"RAW":return e.value}}function $(e,t,n,o){return new Promise((s=>{const i=new Array(4).fill(0).map((()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16))).join("-");t.set(i,s),e.start&&e.start(),e.postMessage(Object.assign({id:i},n),o)}))}function F(e,t,i,r={}){const{maxIterations:a=1e4,tolerance:l=1e-4}=r;let d=[],c=!0,u=0;if(o(`Solving system using ${e}...`),console.time("systemSolving"),"lusolve"===e){const e=math.sparse(t),n=math.slu(e,1,1);let o=math.lusolve(n,i);d=math.squeeze(o).valueOf()}else if("jacobi"===e){const e=function(e,t,n,o={}){const{maxIterations:s,tolerance:i}=o,r=e.length;let a=[...n],l=new Array(r);for(let n=0;n{}))),m.worker.terminate()),{solutionVector:p,converged:b,iterations:u}}class A{constructor({meshDimension:e,elementOrder:t}){this.meshDimension=e,this.elementOrder=t}getBasisFunctions(e,t=null){let n=[],o=[],i=[];if("1D"===this.meshDimension)"linear"===this.elementOrder?(n[0]=1-e,n[1]=e,o[0]=-1,o[1]=1):"quadratic"===this.elementOrder&&(n[0]=1-3*e+2*e**2,n[1]=4*e-4*e**2,n[2]=2*e**2-e,o[0]=4*e-3,o[1]=4-8*e,o[2]=4*e-1);else if("2D"===this.meshDimension){if(null===t)return void s("Eta coordinate is required for 2D elements");if("linear"===this.elementOrder){function r(e){return 1-e}n[0]=r(e)*r(t),n[1]=r(e)*t,n[2]=e*r(t),n[3]=e*t,o[0]=-1*r(t),o[1]=-1*t,o[2]=1*r(t),o[3]=1*t,i[0]=-1*r(e),i[1]=1*r(e),i[2]=-1*e,i[3]=1*e}else if("quadratic"===this.elementOrder){function a(e){return 2*e**2-3*e+1}function l(e){return-4*e**2+4*e}function d(e){return 2*e**2-e}function c(e){return 4*e-3}function u(e){return-8*e+4}function m(e){return 4*e-1}n[0]=a(e)*a(t),n[1]=a(e)*l(t),n[2]=a(e)*d(t),n[3]=l(e)*a(t),n[4]=l(e)*l(t),n[5]=l(e)*d(t),n[6]=d(e)*a(t),n[7]=d(e)*l(t),n[8]=d(e)*d(t),o[0]=c(e)*a(t),o[1]=c(e)*l(t),o[2]=c(e)*d(t),o[3]=u(e)*a(t),o[4]=u(e)*l(t),o[5]=u(e)*d(t),o[6]=m(e)*a(t),o[7]=m(e)*l(t),o[8]=m(e)*d(t),i[0]=a(e)*c(t),i[1]=a(e)*u(t),i[2]=a(e)*m(t),i[3]=l(e)*c(t),i[4]=l(e)*u(t),i[5]=l(e)*m(t),i[6]=d(e)*c(t),i[7]=d(e)*u(t),i[8]=d(e)*m(t)}}return{basisFunction:n,basisFunctionDerivKsi:o,basisFunctionDerivEta:i}}}class w{constructor({numElementsX:e=null,maxX:t=null,numElementsY:n=null,maxY:s=null,meshDimension:i=null,elementOrder:r="linear",parsedMesh:a=null}){this.numElementsX=e,this.numElementsY=n,this.maxX=t,this.maxY=s,this.meshDimension=i,this.elementOrder=r,this.parsedMesh=a,this.boundaryElementsProcessed=!1,this.parsedMesh&&(o("Using pre-parsed mesh from gmshReader data for mesh generation."),this.parseMeshFromGmsh())}parseMeshFromGmsh(){if(this.parsedMesh.nodalNumbering||s("No valid nodal numbering found in the parsed mesh."),Array.isArray(this.parsedMesh.nodalNumbering))return this.boundaryElementsProcessed=!0,this.parsedMesh.boundaryElementsProcessed=!0,this.parsedMesh;if("object"==typeof this.parsedMesh.nodalNumbering&&!Array.isArray(this.parsedMesh.nodalNumbering)){const e=this.parsedMesh.nodalNumbering.quadElements||[];if(this.parsedMesh.nodalNumbering.triangleElements,n("Initial parsed mesh nodal numbering from Gmsh format: "+JSON.stringify(this.parsedMesh.nodalNumbering)),this.parsedMesh.elementTypes[3]||this.parsedMesh.elementTypes[10]){const t=[];for(let n=0;n0&&void 0===this.parsedMesh.boundaryElements[0]){const e=[];for(let t=1;t{if(1===e.dimension){const t=this.parsedMesh.boundaryNodePairs[e.tag]||[];t.length>0&&(this.parsedMesh.boundaryElements[e.tag]||(this.parsedMesh.boundaryElements[e.tag]=[]),t.forEach((t=>{const o=t[0],i=t[1];n(`Processing boundary node pair: [${o}, ${i}] for boundary ${e.tag} (${e.name||"unnamed"})`);let r=!1;for(let t=0;t0&&void 0===this.parsedMesh.boundaryElements[0])){const e=[];for(let t=1;t=-1e-12&&l>=-1e-12&&1-a-l>=-1e-12,ksi:a,eta:l}}function I(e,t,n){const[o,s]=function(e){const[t,n,o,s]=e;return[[t,n,s],[t,o,s]]}(n),i=T(e,t,o),r=T(e,t,s),a=i.inside||r.inside;let l=0,d=0;if(a){const[o,s,i,r]=n,a=(n,o)=>Math.abs((o[0]-n[0])*(n[1]-t)-(n[0]-e)*(o[1]-n[1]))/Math.sqrt((o[0]-n[0])**2+(o[1]-n[1])**2),c=a(o,s),u=a(i,r),m=a(o,i);l=c/(c+u),d=m/(m+a(s,r))}return{inside:a,ksi:l,eta:d}}class R{constructor(e,t,n,o,s){this.boundaryConditions=e,this.boundaryElements=t,this.nop=n,this.meshDimension=o,this.elementOrder=s}imposeConstantTempBoundaryConditions(e,t){"1D"===this.meshDimension?Object.keys(this.boundaryConditions).forEach((o=>{if("constantTemp"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant temperature of ${s} K (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantTemp"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant temperature of ${s} K (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantTemp"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant temperature of ${s} K (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=1,t[r]=s}))}else if("quadratic"===this.elementOrder){({0:[0],2:[2]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=1,t[r]=s}))}}))}})):"2D"===this.meshDimension&&Object.keys(this.boundaryConditions).forEach((o=>{if("constantTemp"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant temperature of ${s} K (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=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[o][i]-1;n(` - Applied constant temperature to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=1,t[r]=s}))}}))}}))}imposeConvectionBoundaryConditions(e,t,o,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((o=>{if("convection"===this.boundaryConditions[o][0]){const s=l[o],i=d[o];n(`Boundary ${o}: Applying convection with heat transfer coefficient h=${s} W/(m²·K) and external temperature T∞=${i} K`),this.boundaryElements[o].forEach((([o,r])=>{let a;"linear"===this.elementOrder?a=0===r?0:1:"quadratic"===this.elementOrder&&(a=0===r?0:2);const l=this.nop[o][a]-1;n(` - Applied convection boundary condition to node ${l+1} (element ${o+1}, local node ${a+1})`),e[l]+=-s*i,t[l][l]+=s}))}})):"2D"===this.meshDimension&&Object.keys(this.boundaryConditions).forEach((c=>{if("convection"===this.boundaryConditions[c][0]){const u=l[c],m=d[c];n(`Boundary ${c}: Applying convection with heat transfer coefficient h=${u} W/(m²·K) and external temperature T∞=${m} K`),this.boundaryElements[c].forEach((([l,d])=>{if("linear"===this.elementOrder){let c,h,f,p,b;0===d?(c=o[0],h=0,f=0,p=3,b=2):1===d?(c=0,h=o[0],f=0,p=2,b=1):2===d?(c=o[0],h=1,f=1,p=4,b=2):3===d&&(c=1,h=o[0],f=2,p=4,b=1);let g=a.getBasisFunctions(c,h),y=g.basisFunction,E=g.basisFunctionDerivKsi,v=g.basisFunctionDerivEta,C=0,M=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,c=Array(d).fill().map((()=>Array(d).fill(0))),u=Array(d).fill(0);for(const m in this.boundaryElements)if("convection"===this.boundaryConditions[m]?.[0]){const h=a[m],f=l[m];n(`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),n(` - Applied convection boundary condition to node ${t+1} (element ${e+1}, local node ${t+1})`),u[t]+=-h*f,c[t][t]+=h}else if("2D"===this.meshDimension)if("linear"===this.elementOrder){let n,l,m,p,b;0===a?(n=s[0],l=0,m=0,p=3,b=2):1===a?(n=0,l=s[0],m=0,p=2,b=1):2===a?(n=s[0],l=1,m=1,p=4,b=2):3===a&&(n=1,l=s[0],m=2,p=4,b=1);const g=r.getBasisFunctions(n,l),y=g.basisFunction,E=g.basisFunctionDerivKsi,v=g.basisFunctionDerivEta;let C,M=0,D=0,$=0,F=0;for(let n=0;nArray(a).fill(0))),m=Array(a).fill(0),h=Array(a),f=Array(a);for(let n=0;ne-1)),{detJacobian:f,basisFunctionDerivX:p,basisFunctionDerivY:b}=k({basisFunction:n,basisFunctionDerivKsi:s,basisFunctionDerivEta:c,nodesXCoordinates:l,nodesYCoordinates:d,localToGlobalMap:m,nodesPerElement:a});for(let n=0;n{if("constantValue"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant value of ${s} (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantValue"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant value of ${s} (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=s;for(let n=0;n{if("constantValue"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant value of ${s} (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0],1:[1]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=1,t[r]=s}))}else if("quadratic"===this.elementOrder){({0:[0],2:[2]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=1,t[r]=s}))}}))}})):"2D"===this.meshDimension&&Object.keys(this.boundaryConditions).forEach((o=>{if("constantValue"===this.boundaryConditions[o][0]){const s=this.boundaryConditions[o][1];n(`Boundary ${o}: Applying constant value of ${s} (Dirichlet condition)`),this.boundaryElements[o].forEach((([o,i])=>{if("linear"===this.elementOrder){({0:[0,2],1:[0,1],2:[1,3],3:[2,3]})[i].forEach((i=>{const r=this.nop[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=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[o][i]-1;n(` - Applied constant value to node ${r+1} (element ${o+1}, local node ${i+1})`),e[r]=1,t[r]=s}))}}))}}))}}function q(e,t,s,i){o("Starting front propagation matrix assembly...");let r=1-i+.01;n(`eikonalViscousTerm: ${r}`),n(`eikonalActivationFlag: ${i}`);const{nodesXCoordinates:a,nodesYCoordinates:l,nop:d,boundaryElements:c,totalElements:u,meshDimension:m,elementOrder:h}=e,f=V(e),{residualVector:p,jacobianMatrix:b,localToGlobalMap:g,basisFunctions:y,gaussPoints:E,gaussWeights:v,nodesPerElement:C}=f;for(let e=0;eArray(d).fill(0))),p=Array(d).fill(0),b=Array(d),g=Array(d);for(let n=0;nArray(e).fill(0))),G.nodeConstraintCode=Array(e).fill(0),G.boundaryValues=Array(e).fill(0),G.globalResidualVector=Array(e).fill(0),G.solutionVector=Array(e).fill(0),G.topologyData=Array(t).fill(0),G.lateralData=Array(t).fill(0),K.writeFlag=0,K.totalNodes=e,K.transformationFlag=0,K.nodesPerElement=Array(t).fill(0),K.determinant=1;const n=Math.max(e,2e3);K.globalSolutionVector=Array(n).fill(0),K.frontDataIndex=0,J.localJacobianMatrix=Array(e).fill().map((()=>Array(e).fill(0))),J.currentElementIndex=0;const o=function(e,t){const n=Math.max(Math.ceil(Math.sqrt(t))*e,2*e);return n*t}(e,t);L.frontValues=Array(o).fill(0),L.columnHeaders=Array(n).fill(0),L.pivotRow=Array(n).fill(0),L.pivotData=Array(o).fill(0)}(a.nodesPerElement,d),o("Solving system using frontal..."),console.time("systemSolving"),H=new A({meshDimension:t.meshDimension,elementOrder:t.elementOrder});for(let e=0;eArray(l).fill(0))),y=Array(a).fill(0),E=Array(a).fill(0),v=Array(a).fill(0),C=1;K.writeFlag++;let M=1,D=1;J.currentElementIndex=0;for(let e=0;el||$>l)return void s("Error: systemSize not large enough");for(let e=0;e0)for(let e=0;eD||J.currentElementIndexMath.abs(o)&&(o=r,t=s,e=i)}}}let i=Math.abs(m[e-1]);d=Math.abs(L.columnHeaders[t-1]);let a=i+d+y[i-1]+E[d-1];K.determinant=K.determinant*o*(-1)**a/Math.abs(o);for(let e=0;e=i&&y[e]--,e>=d&&E[e]--;if(Math.abs(o)<1e-10&&s(`Matrix singular or ill-conditioned, currentElementIndex=${J.currentElementIndex}, pivotGlobalRowIndex=${i}, pivotColumnGlobalIndex=${d}, pivotValue=${o}`),0===o)return;for(let t=0;t<$;t++)L.pivotRow[t]=g[e-1][t]/o;let l=G.globalResidualVector[i-1]/o;if(G.globalResidualVector[i-1]=l,b[e-1]=o,e>1)for(let n=0;n1&&0!==o)for(let e=0;e1)for(let e=0;e1||J.currentElementIndex=e.totalElements)return s(`Skipping out-of-range elementIndex=${i} (totalElements=${e.totalElements})`),!1;const{localJacobianMatrix:r,localResidualVector:a,ngl:l}=o({elementIndex:i,nop:G.nodalNumbering,meshData:e,basisFunctions:H,FEAData:t,solutionVector:K.currentSolutionVector,eikonalActivationFlag:K.eikonalActivationFlag});let d=Array(t.nodesPerElement).fill().map((()=>Array(t.nodesPerElement).fill(0))),c=Array(t.nodesPerElement).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===i))){o=!0;break}if(o){const{gaussPoints:o,gaussWeights:s}=t,r=n.imposeConvectionBoundaryConditionsFront(i,e.nodesXCoordinates,e.nodesYCoordinates,o,s,H);d=r.localJacobianMatrix,c=r.localResidualVector}}for(let e=0;e0)continue;let r=0;L.pivotRow[s-1]=0;for(let e=0;e100){s(`Solution not converged. Error norm: ${i}`);break}a++}return{solutionVector:d,converged:r,iterations:a,jacobianMatrix:c,residualVector:u}}function Z(e,t,n,o,s,i,r){const{nodesXCoordinates:a,nodesYCoordinates:l}=n.nodesCoordinates,d=t.nop[o].length;if(4===d){const d=I(s,i,[[a[t.nop[o][0]-1],l[t.nop[o][0]-1]],[a[t.nop[o][1]-1],l[t.nop[o][1]-1]],[a[t.nop[o][2]-1],l[t.nop[o][2]-1]],[a[t.nop[o][3]-1],l[t.nop[o][3]-1]]]);if(d.inside)return{inside:!0,value:ee(e,t,n,o,d.ksi,d.eta,r)}}else if(9===d){const d=I(s,i,[[a[t.nop[o][0]-1],l[t.nop[o][0]-1]],[a[t.nop[o][2]-1],l[t.nop[o][2]-1]],[a[t.nop[o][6]-1],l[t.nop[o][6]-1]],[a[t.nop[o][8]-1],l[t.nop[o][8]-1]]]);if(d.inside)return{inside:!0,value:ee(e,t,n,o,d.ksi,d.eta,r)}}return{inside:!1,value:null}}function ee(e,t,n,o,s,i,r){const a=n.solutionVector,l=t.nop[o].length;let d,c=r.getBasisFunctions(s,i).basisFunction;d=Array.isArray(a[0])?a.map((e=>e[0])):a;let u=0;for(let e=0;et!=l>t&&e<(a-i)*(t-r)/(l-r)+i&&(o=!o)}return o}exports.FEAScriptModel=class{constructor(){var e;this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",this.coefficientFunctions=null,e="FEAScript is provided “as is” without any warranty. The authors are not responsible for any damages or losses that may result from using the software. See the license for more details: https://github.com/FEAScript/FEAScript-core/blob/main/LICENSE",console.log("%c[WARN] "+e,"color: #FF9800; font-weight: bold;"),o("FEAScriptModel instance created")}setSolverConfig(e,t={}){this.solverConfig=e,t?.coefficientFunctions&&(this.coefficientFunctions=t.coefficientFunctions,n("Coefficient functions set")),void 0!==t?.maxIterations&&(this.maxIterations=t.maxIterations),void 0!==t?.tolerance&&(this.tolerance=t.tolerance),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(e={}){this.solverConfig&&this.meshConfig&&this.boundaryConditions||s("Solver config, mesh config, and boundary conditions must be set before solving.");let t=[],n=[],i=[],r=[];o("Preparing mesh...");const a=X(this.meshConfig);o("Mesh preparation completed");const l={nodesXCoordinates:a.nodesXCoordinates,nodesYCoordinates:a.nodesYCoordinates};if(o("Beginning solving process..."),console.time("totalSolvingTime"),o(`Using solver: ${this.solverConfig}`),"heatConductionScript"===this.solverConfig)if("frontal"===this.solverMethod){i=U(B,a,this.boundaryConditions).solutionVector}else{({jacobianMatrix:t,residualVector:n}=Y(a,this.boundaryConditions));i=F(this.solverMethod,t,n,{maxIterations:e.maxIterations??this.maxIterations,tolerance:e.tolerance??this.tolerance}).solutionVector}else if("frontPropagationScript"===this.solverConfig){let o=0;const s=5,l={meshData:a,boundaryConditions:this.boundaryConditions,eikonalActivationFlag:o,solverMethod:this.solverMethod,initialSolution:r,maxIterations:e.maxIterations??this.maxIterations,tolerance:e.tolerance??this.tolerance};for(;o<=1;){l.eikonalActivationFlag=o,i.length>0&&(l.initialSolution=[...i]);const e=Q(q,l);t=e.jacobianMatrix,n=e.residualVector,i=e.solutionVector,o+=1/s}}else if("generalFormPDEScript"===this.solverConfig)if("frontal"===this.solverMethod)s("Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.");else{({jacobianMatrix:t,residualVector:n}=function(e,t,n){o("Starting general form PDE matrix assembly...");const{nodesXCoordinates:i,nodesYCoordinates:r,nop:a,boundaryElements:l,totalElements:d,meshDimension:c,elementOrder:u}=e,{A:m,B:h,C:f,D:p}=n,b=V(e),{residualVector:g,jacobianMatrix:y,localToGlobalMap:E,basisFunctions:v,gaussPoints:C,gaussWeights:M,nodesPerElement:D}=b;if("1D"===c)for(let e=0;e{console.error("FEAScriptWorker: Worker error:",e)};const e=f(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},c=0,u=[],m=0,h=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},b=0,g={};for(;i""!==e));if("meshFormat"===s)t.gmshV=parseFloat(n[0]),t.ascii="0"===n[1],t.fltBytes=n[2];else if("physicalNames"===s){if(n.length>=3){if(!/^\d+$/.test(n[0])){i++;continue}const e=parseInt(n[0],10),o=parseInt(n[1],10);let s=n.slice(2).join(" ");s=s.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:o,dimension:e,name:s})}}else if("nodes"===s){if(0===r){r=parseInt(n[0],10),a=parseInt(n[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;g[n]||(g[n]=[]),g[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);b++,b===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=g[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),n(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t},exports.logSystem=function(e){"basic"!==e&&"debug"!==e?(console.log("%c[WARN] Invalid log level: "+e+". Using basic instead.","color: #FFC107; font-weight: bold;"),t="basic"):(t=e,o(`Log level set to: ${e}`))},exports.plotInterpolatedSolution=function(e,t,n,o){const{nodesXCoordinates:s,nodesYCoordinates:i}=t.nodesCoordinates,r=e.meshConfig.meshDimension,a=X(e.meshConfig),l=new A({meshDimension:e.meshConfig.meshDimension,elementOrder:e.meshConfig.elementOrder});if("1D"===r&&"line"===n);else if("2D"===r&&"contour"===n){const r=[],d=[];let c=[];const u=100,m=100,h=(Math.max(...s)-Math.min(...s))/(u-1),f=(Math.max(...i)-Math.min(...i))/(m-1);r[0]=Math.min(...s),d[0]=Math.min(...i);for(let e=1;e[])),r=Array(o).fill(0);for(let e=0;e0&&Array.isArray(r[0])?r.map((e=>e[0])):r,Array.from(s);let t={x:s,y:e,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},n=Math.min(window.innerWidth,700),i={title:`line plot - ${a}`,width:Math.min(n,600),height:300,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:50,r:50,t:50,b:50}};Plotly.newPlot(o,[t],i,{responsive:!0})}else if("2D"===l&&"contour"===n){let e;e=Array.isArray(r[0])?r.map((e=>e[0])):r;let t=Math.min(window.innerWidth,700),l=Math.max(...s),d=Math.max(...i)/l,c=Math.min(t,600),u={title:`${n} plot - ${a}`,width:c,height:c*d,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"},m={x:s,y:i,z:e,type:"contour",line:{smoothing:.85},contours:{coloring:"heatmap",showlabels:!1},colorbar:{title:"Solution"},name:"Solution Field"};Plotly.newPlot(o,[m],u,{responsive:!0})}},exports.printVersion="0.2.0 (RC)"; //# sourceMappingURL=feascript.cjs.js.map diff --git a/dist/feascript.cjs.js.map b/dist/feascript.cjs.js.map index 43859eb..b52d4ef 100644 --- a/dist/feascript.cjs.js.map +++ b/dist/feascript.cjs.js.map @@ -1 +1 @@ -{"version":3,"file":"feascript.cjs.js","sources":["../src/methods/euclideanNormScript.js","../src/utilities/loggingScript.js","../src/vendor/comlink.mjs","../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/models/thermalBoundaryConditionsScript.js","../src/models/heatConductionScript.js","../src/models/genericBoundaryConditionsScript.js","../src/models/frontPropagationScript.js","../src/methods/frontalSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/FEAScript.js","../src/models/generalFormPDEScript.js","../src/workers/workerScript.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.js","../src/index.js"],"sourcesContent":["/**\n * ════════════════════════════════════════════════════════════\n * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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;\");\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;\");\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;\");\n}\n\n/**\n * Function to log warning messages\n * @param {string} message - Message to log\n */\nexport function warnLog(message) {\n console.log(\"%c[WARN] \" + message, \"color: #FF9800; font-weight: bold;\");\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 * @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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { jacobiSolver } from \"./jacobiSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\nimport * as Comlink from \"../vendor/comlink.mjs\";\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] - Optional parameters for the solver, such as `maxIterations` and `tolerance`\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\n // Extract options\n const { maxIterations = 10000, tolerance = 1e-4 } = 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// Helper to lazily create a default WebGPU compute engine (Comlink + worker)\nasync function createDefaultComputeEngine() {\n const worker = new Worker(new URL(\"../workers/webgpuWorkerScript.js\", import.meta.url), {\n type: \"module\",\n });\n const computeEngine = Comlink.wrap(worker);\n await computeEngine.initialize();\n return { computeEngine, worker };\n}\n\n/**\n * Function to solve asynchronously a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (e.g., \"jacobi-gpu\")\n * @param {array} jacobianMatrix - The coefficient matrix\n * @param {array} residualVector - The right-hand side vector\n * @param {object} [options] - Optional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {Promise} A promise that resolves to 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 async function solveLinearSystemAsync(solverMethod, jacobianMatrix, residualVector, options = {}) {\n \n // Extract options\n const { maxIterations = 10000, tolerance = 1e-4 } = options;\n\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n // Normalize inputs\n const A = Array.isArray(jacobianMatrix) ? jacobianMatrix : jacobianMatrix?.toArray?.() ?? jacobianMatrix;\n const b = Array.isArray(residualVector) ? residualVector : residualVector?.toArray?.() ?? residualVector;\n\n let created = null;\n let computeEngine = null;\n\n let solutionVector = [];\n let converged = true;\n let iterations;\n\n if (solverMethod === \"jacobi-gpu\") {\n // Spin up a worker-backed compute engine\n created = await createDefaultComputeEngine();\n computeEngine = created.computeEngine;\n\n const x0 = new Array(b.length).fill(0);\n let result;\n\n result = await computeEngine.webgpuJacobiSolver(A, b, x0, { maxIterations, tolerance });\n solutionVector = result.solutionVector;\n converged = result.converged;\n iterations = result.iterations;\n\n // Log convergence information\n if (converged) {\n debugLog(`Jacobi method converged in ${iterations} iterations`);\n } else {\n errorLog(`Jacobi method did not converge after ${iterations} iterations`);\n }\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(`System solved successfully (${solverMethod})`);\n\n if (created) {\n await computeEngine?.destroy?.().catch(() => { });\n created.worker.terminate();\n }\n\n return { solutionVector, converged, iterations };\n}\n","/**\n * ════════════════════════════════════════════════════════════\n * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method (CPU synchronous version)\n * @param {array} A - The system matrix\n * @param {array} b - The right-hand side vector\n * @param {array} x0 - Initial guess for solution vector\n * @param {object} [options] - Optional parameters for the solver, such as `maxIterations` and `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(A, b, x0, options = {}) {\n // Extract options\n const { maxIterations, tolerance } = options;\n\n const n = A.length;\n let x = [...x0];\n let xNew = new Array(n);\n\n // Jacobi update: xNew[i] = (b[i] - sum(A[i][j] * x[j] for j != i)) / A[i][i]\n for (let iter = 0; iter < maxIterations; iter++) {\n for (let i = 0; i < n; i++) {\n let sum = 0;\n for (let j = 0; j < n; j++) {\n if (i !== j) {\n sum += A[i][j] * x[j];\n }\n }\n xNew[i] = (b[i] - sum) / A[i][i];\n }\n\n // Check convergence based on maximum difference in solution vector\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 // Copy new solution for the next iteration\n x = [...xNew];\n\n if (maxDiff < tolerance) {\n return { solutionVector: x, iterations: iter + 1, converged: true };\n }\n }\n\n return { solutionVector: x, iterations: maxIterations, converged: false };\n}\n","/**\n * ════════════════════════════════════════════════════════════\n * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { initializeFEA } from \"../mesh/meshUtilsScript.js\";\nimport { assembleHeatConductionFront } from \"../models/heatConductionScript.js\";\nimport { ThermalBoundaryConditions } from \"../models/thermalBoundaryConditionsScript.js\";\nimport { assembleFrontPropagationFront } from \"../models/frontPropagationScript.js\";\nimport { GenericBoundaryConditions } from \"../models/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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 \"../models/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 * @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 = {}) {\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 // Extract context\n const { maxIterations = 100, tolerance = 1e-4 } = context;\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { solveLinearSystemAsync } from \"./methods/linearSystemSolverScript.js\";\nimport { prepareMesh } from \"./mesh/meshUtilsScript.js\";\nimport { assembleFrontPropagationMat } from \"./models/frontPropagationScript.js\";\nimport { assembleGeneralFormPDEMat, assembleGeneralFormPDEFront } from \"./models/generalFormPDEScript.js\";\nimport { assembleHeatConductionMat, assembleHeatConductionFront } from \"./models/heatConductionScript.js\";\nimport { runFrontalSolver } from \"./methods/frontalSolverScript.js\";\nimport { basicLog, debugLog, warnLog, 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 containifng 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 warnLog(\n \"FEAScript is provided “as is” without any warranty. The authors are not responsible for any damages or losses that may result from using the software. See the license for more details: https://github.com/FEAScript/FEAScript-core/blob/main/LICENSE\"\n );\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?.coefficientFunctions) {\n this.coefficientFunctions = options.coefficientFunctions;\n debugLog(\"Coefficient functions set\");\n }\n // Only update if a value is provided, otherwise keep the default\n if (options?.maxIterations !== undefined) {\n this.maxIterations = options.maxIterations;\n }\n if (options?.tolerance !== undefined) {\n this.tolerance = options.tolerance;\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 /**\n * Function to solve the finite element problem synchronously\n * @param {object} [options] - Additional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {object} An object containing the solution vector and the coordinates of the mesh nodes\n */\n solve(options = {}) {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n errorLog(\"Solver config, mesh config, and boundary conditions must be set before solving.\");\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 basicLog(`Using solver: ${this.solverConfig}`);\n if (this.solverConfig === \"heatConductionScript\") {\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 maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n });\n solutionVector = linearSystemResult.solutionVector;\n }\n } else if (this.solverConfig === \"frontPropagationScript\") {\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 // TODO: Consider using different maxIterations/tolerance for Newton-Raphson and linear solver\n maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\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);\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 // 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 maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n });\n solutionVector = linearSystemResult.solutionVector;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n\n /**\n * Function to solve the finite element problem asynchronously\n * @param {object} computeEngine - The compute engine to use for the asynchronous solver (e.g., a worker or a WebGPU context)\n * @param {object} [options] - Additional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {Promise} A promise that resolves to an object containing the solution vector and the coordinates of the mesh nodes\n */\n async solveAsync(computeEngine, options = {}) {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n errorLog(\"Solver config, mesh config, and boundary conditions must be set before solving.\");\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n\n basicLog(\"Preparing mesh...\");\n const meshData = prepareMesh(this.meshConfig);\n basicLog(\"Mesh preparation completed\");\n const nodesCoordinates = {\n nodesXCoordinates: meshData.nodesXCoordinates,\n nodesYCoordinates: meshData.nodesYCoordinates,\n };\n\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n\n basicLog(`Using solver: ${this.solverConfig}`);\n if (this.solverConfig === \"heatConductionScript\") {\n ({ jacobianMatrix, residualVector } = assembleHeatConductionMat(meshData, this.boundaryConditions));\n\n if (this.solverMethod === \"jacobi-gpu\") {\n const { solutionVector: x } = await solveLinearSystemAsync(\"jacobi-gpu\", jacobianMatrix, residualVector, {\n computeEngine,\n maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n });\n solutionVector = x;\n } else {\n // Other async solver\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n\n}\n","/**\n * ════════════════════════════════════════════════════════════\n * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId\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: nodesXCoordinates,\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 plotWidth = Math.min(maxWindowWidth, 600);\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: 50, r: 50, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Check if solutionVector is a nested array\n let zData;\n if (Array.isArray(solutionVector[0])) {\n zData = solutionVector.map((val) => val[0]);\n } else {\n zData = solutionVector;\n }\n\n // Sizing parameters\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;\n\n // 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 // Create the plot\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zData,\n type: \"contour\",\n line: {\n smoothing: 0.85,\n },\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 Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n}\n","/**\n * ════════════════════════════════════════════════════════════\n * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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.4\";"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","debugLog","message","console","log","basicLog","errorLog","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","value","serialized","Error","isError","name","stack","Object","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","map","fromWireValue","returnValue","parent","slice","reduce","prop","rawValue","apply","proxy","transfers","transferCache","set","transfer","undefined","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","constructor","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","Array","prototype","concat","handler","serializedValue","msg","fill","floor","random","Number","MAX_SAFE_INTEGER","join","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","jacobianMatrixSparse","math","sparse","luFactorization","slu","solutionMatrix","lusolve","squeeze","valueOf","jacobiSolverResult","A","b","x0","n","x","xNew","iter","sum","j","maxDiff","max","abs","jacobiSolver","timeEnd","async","solveLinearSystemAsync","isArray","toArray","created","computeEngine","worker","Worker","URL","document","require","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","Comlink.wrap","initialize","createDefaultComputeEngine","result","webgpuJacobiSolver","destroy","terminate","BasisFunctions","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","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","boundaryElements","fixedBoundaryElements","boundaryNodePairs","forEach","dimension","tag","nodesPair","node1","node2","foundElement","elemNodes","includes","side","node1Index","indexOf","node2Index","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","prepareMesh","meshConfig","mesh","nodesCoordinatesAndNumbering","totalElements","totalNodes","initializeFEA","meshData","colIndex","basisFunctions","gaussPointsAndWeights","localToGlobalMap","numNodes","performIsoparametricMapping1D","params","xCoordinates","ksiDerivX","localNodeIndex","detJacobian","basisFunctionDerivX","performIsoparametricMapping2D","yCoordinates","etaDerivX","ksiDerivY","etaDerivY","basisFunctionDerivY","ThermalBoundaryConditions","boundaryConditions","imposeConstantTempBoundaryConditions","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","localResidualVector","boundaryElement","find","_","assembleHeatConductionMat","FEAData","gaussPointIndex1","mappingResult","localNodeIndex1","localToGlobalMap1","localToGlobalMap2","gaussPointIndex2","thermalBoundaryConditions","assembleHeatConductionFront","ngl","globalIndex","GenericBoundaryConditions","imposeDirichletBoundaryConditions","imposeConstantValueBoundaryConditionsFront","assembleFrontPropagationMat","eikonalActivationFlag","eikonalViscousTerm","solutionDerivX","solutionDerivY","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","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","nodesCoordinates","boundaryLocalJacobianMatrix","boundaryResidualVector","isOnRobinTypeBoundary","some","localNodeI","localNodeJ","iterationIndex","accumulatedValue","newtonRaphson","assembleMat","context","errorNorm","initialSolution","solverConfig","coefficientFunctions","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","eikonalExteralIterations","newtonRaphsonResult","B","C","D","xCoord","a","d","globalNodeIndex1","assembleGeneralFormPDEMat","solveAsync","feaWorker","isReady","_initWorker","onerror","event","workerWrapper","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","toFixed","getModelInfo","ping","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","yData","from","lineData","mode","color","width","maxWindowWidth","min","window","innerWidth","layout","title","height","xaxis","yaxis","margin","l","t","Plotly","newPlot","responsive","zData","aspectRatio","plotWidth","hovermode","contourData","z","smoothing","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/vendor/comlink.mjs","../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/models/thermalBoundaryConditionsScript.js","../src/models/heatConductionScript.js","../src/models/genericBoundaryConditionsScript.js","../src/models/frontPropagationScript.js","../src/methods/frontalSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/visualization/plotSolutionScript.js","../src/FEAScript.js","../src/models/generalFormPDEScript.js","../src/workers/workerScript.js","../src/readers/gmshReaderScript.js","../src/index.js"],"sourcesContent":["/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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;\");\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;\");\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;\");\n}\n\n/**\n * Function to log warning messages\n * @param {string} message - Message to log\n */\nexport function warnLog(message) {\n console.log(\"%c[WARN] \" + message, \"color: #FF9800; font-weight: bold;\");\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 * @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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { jacobiSolver } from \"./jacobiSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\nimport * as Comlink from \"../vendor/comlink.mjs\";\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] - Optional parameters for the solver, such as `maxIterations` and `tolerance`\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\n // Extract options\n const { maxIterations = 10000, tolerance = 1e-4 } = 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// Helper to lazily create a default WebGPU compute engine (Comlink + worker)\nasync function createDefaultComputeEngine() {\n const worker = new Worker(new URL(\"../workers/webgpuWorkerScript.js\", import.meta.url), {\n type: \"module\",\n });\n const computeEngine = Comlink.wrap(worker);\n await computeEngine.initialize();\n return { computeEngine, worker };\n}\n\n/**\n * Function to solve asynchronously a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (e.g., \"jacobi-gpu\")\n * @param {array} jacobianMatrix - The coefficient matrix\n * @param {array} residualVector - The right-hand side vector\n * @param {object} [options] - Optional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {Promise} A promise that resolves to 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 async function solveLinearSystemAsync(solverMethod, jacobianMatrix, residualVector, options = {}) {\n \n // Extract options\n const { maxIterations = 10000, tolerance = 1e-4 } = options;\n\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n // Normalize inputs\n const A = Array.isArray(jacobianMatrix) ? jacobianMatrix : jacobianMatrix?.toArray?.() ?? jacobianMatrix;\n const b = Array.isArray(residualVector) ? residualVector : residualVector?.toArray?.() ?? residualVector;\n\n let created = null;\n let computeEngine = null;\n\n let solutionVector = [];\n let converged = true;\n let iterations;\n\n if (solverMethod === \"jacobi-gpu\") {\n // Spin up a worker-backed compute engine\n created = await createDefaultComputeEngine();\n computeEngine = created.computeEngine;\n\n const x0 = new Array(b.length).fill(0);\n let result;\n\n result = await computeEngine.webgpuJacobiSolver(A, b, x0, { maxIterations, tolerance });\n solutionVector = result.solutionVector;\n converged = result.converged;\n iterations = result.iterations;\n\n // Log convergence information\n if (converged) {\n debugLog(`Jacobi method converged in ${iterations} iterations`);\n } else {\n errorLog(`Jacobi method did not converge after ${iterations} iterations`);\n }\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(`System solved successfully (${solverMethod})`);\n\n if (created) {\n await computeEngine?.destroy?.().catch(() => { });\n created.worker.terminate();\n }\n\n return { solutionVector, converged, iterations };\n}\n","/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method (CPU synchronous version)\n * @param {array} A - The system matrix\n * @param {array} b - The right-hand side vector\n * @param {array} x0 - Initial guess for solution vector\n * @param {object} [options] - Optional parameters for the solver, such as `maxIterations` and `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(A, b, x0, options = {}) {\n // Extract options\n const { maxIterations, tolerance } = options;\n\n const n = A.length;\n let x = [...x0];\n let xNew = new Array(n);\n\n // Jacobi update: xNew[i] = (b[i] - sum(A[i][j] * x[j] for j != i)) / A[i][i]\n for (let iter = 0; iter < maxIterations; iter++) {\n for (let i = 0; i < n; i++) {\n let sum = 0;\n for (let j = 0; j < n; j++) {\n if (i !== j) {\n sum += A[i][j] * x[j];\n }\n }\n xNew[i] = (b[i] - sum) / A[i][i];\n }\n\n // Check convergence based on maximum difference in solution vector\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 // Copy new solution for the next iteration\n x = [...xNew];\n\n if (maxDiff < tolerance) {\n return { solutionVector: x, iterations: iter + 1, converged: true };\n }\n }\n\n return { solutionVector: x, iterations: maxIterations, converged: false };\n}\n","/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 this parsed mesh was already converted in a previous run, don't re-process it.\n // Just mark this Mesh instance as ready so prepareMesh() doesn't fall back to generateMesh().\n if (Array.isArray(this.parsedMesh.nodalNumbering)) {\n this.boundaryElementsProcessed = true;\n this.parsedMesh.boundaryElementsProcessed = true;\n return this.parsedMesh;\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 elementIndex = 0; elementIndex < quadElements.length; elementIndex++) {\n const gmshNodes = quadElements[elementIndex];\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 (\n let elementIndex = 0;\n elementIndex < this.parsedMesh.nodalNumbering.length;\n elementIndex++\n ) {\n const elementConnectivity = this.parsedMesh.nodalNumbering[elementIndex];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elementConnectivity.length === 4) {\n // Check if both boundary nodes are in this element\n if (elementConnectivity.includes(node1) && elementConnectivity.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elementConnectivity.indexOf(node1);\n const node2Index = elementConnectivity.indexOf(node2);\n\n debugLog(\n ` Found element ${elementIndex} containing boundary nodes. Element nodes: [${elementConnectivity.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 ${elementIndex}`);\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 ${elementIndex}`);\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 ${elementIndex}`);\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 ${elementIndex}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elementIndex, side]);\n debugLog(\n ` Added element-side pair [${elementIndex}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elementConnectivity.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elementConnectivity.includes(node1) && elementConnectivity.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elementConnectivity.indexOf(node1);\n const node2Index = elementConnectivity.indexOf(node2);\n\n debugLog(\n ` Found element ${elementIndex} containing boundary nodes. Element nodes: [${elementConnectivity.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 ${elementIndex}`);\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 ${elementIndex}`);\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 ${elementIndex}`);\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 ${elementIndex}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elementIndex, side]);\n debugLog(\n ` Added element-side pair [${elementIndex}, ${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.generateNodalNumbering1D(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 generateNodalNumbering1D(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 an 1D 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 * 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; // Two sides for 1D case (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.generateNodalNumbering2D(\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 generateNodalNumbering2D(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 2D 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 * 0 - Bottom side of reference element (maps to physical bottom boundary in the case of a rectangular domain)\n * 1 - Left side of reference element (maps to physical left boundary in the case of a rectangular domain)\n * 2 - Top side of reference element (maps to physical top boundary in the case of a rectangular domain)\n * 3 - Right side of reference element (maps to physical right boundary in the case of a rectangular domain)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // Four sides for a rectangle 2D case (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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n// Internal imports\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 (e.g., from a Gmsh .msh import) if provided. Otherwise, generate a structured mesh\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 nodesPerElement = nop[0].length;\n\n return {\n residualVector,\n jacobianMatrix,\n localToGlobalMap,\n basisFunctions,\n gaussPoints,\n gaussWeights,\n nodesPerElement,\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, nodesPerElement } =\n params;\n\n let xCoordinates = 0;\n let ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; 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 < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; 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 < nodesPerElement; 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 * Function to test if a point is inside a triangle using barycentric coordinates,\n * also returning the natural coordinates (ksi, eta).\n * @param {number} x - X-coordinate of the point\n * @param {number} y - Y-coordinate of the point\n * @param {array} vertices - Triangle vertices [[x0,y0],[x1,y1],[x2,y2]]\n * @returns {object} Object containing inside boolean and natural coordinates {inside, ksi, eta}\n */\nexport function pointInsideTriangle(x, y, vertices) {\n const tolerance = 1e-12;\n const [v0, v1, v2] = vertices;\n\n const denom = (v1[1] - v2[1]) * (v0[0] - v2[0]) + (v2[0] - v1[0]) * (v0[1] - v2[1]);\n\n const ksi = ((v1[1] - v2[1]) * (x - v2[0]) + (v2[0] - v1[0]) * (y - v2[1])) / denom;\n const eta = ((v2[1] - v0[1]) * (x - v2[0]) + (v0[0] - v2[0]) * (y - v2[1])) / denom;\n const gamma = 1 - ksi - eta;\n\n const inside = ksi >= -tolerance && eta >= -tolerance && gamma >= -tolerance;\n return { inside, ksi, eta };\n}\n\n/**\n * Function to test if a point is inside a quadrilateral by spliting it into triangles and using barycentric coordinates\n * @param {number} x - X-coordinate of the point\n * @param {number} y - Y-coordinate of the point\n * @param {array} vertices - Quadrilateral vertices [[x0,y0],[x1,y1],[x2,y2],[x3,y3]]\n * @returns {object} Object containing inside boolean and natural coordinates {inside, ksi, eta}\n */\nexport function pointInsideQuadrilateral(x, y, vertices) {\n const [firstTriangleVertices, secondTriangleVertices] = splitQuadrilateral(vertices);\n const pointInsideFirstTriangle = pointInsideTriangle(x, y, firstTriangleVertices);\n const pointInsideSecondTriangle = pointInsideTriangle(x, y, secondTriangleVertices);\n\n const inside = pointInsideFirstTriangle.inside || pointInsideSecondTriangle.inside;\n let ksi = 0;\n let eta = 0;\n\n if (inside) {\n const [v0, v1, v2, v3] = vertices;\n\n // Function to calculate distance from point to line segment\n const getDistanceFromLine = (p1, p2) => {\n const num = Math.abs((p2[0] - p1[0]) * (p1[1] - y) - (p1[0] - x) * (p2[1] - p1[1]));\n const den = Math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2);\n return num / den;\n };\n\n // Calculate distances to edges based on vertex order:\n // 1 (v1) --- 3 (v3)\n // | |\n // 0 (v0) --- 2 (v2)\n\n const distLeft = getDistanceFromLine(v0, v1);\n const distRight = getDistanceFromLine(v2, v3);\n const distBottom = getDistanceFromLine(v0, v2);\n const distTop = getDistanceFromLine(v1, v3);\n\n ksi = distLeft / (distLeft + distRight);\n eta = distBottom / (distBottom + distTop);\n }\n\n return { inside, ksi, eta };\n}\n\n/**\n * Function to split the quadrilateral elements into two triangles\n * @param {array} vertices - Quadrilateral vertices [[x0,y0],[x1,y1],[x2,y2],[x3,y3]]\n * @returns {array} Array of triangle vertices: [[v0,v1,v3], [v0,v2,v3]]\n */\nexport function splitQuadrilateral(vertices) {\n const [v0, v1, v2, v3] = vertices;\n // Vertices order:\n // 1 --- 3\n // | |\n // 0 --- 2\n return [\n [v0, v1, v3],\n [v0, v2, v3],\n ];\n}\n\n/**\n * Function that finds the list of adjacent elements for each node in the mesh\n * @param {object} meshData - Object containing nodal numbering (NOP)\n * @returns {object} Object containing:\n * - nodeNeighbors: Indices of neighboring elements per node\n * - neighborCount: Total number of neighboring elements per node\n */\nexport function computeNodeNeighbors(meshData) {\n const { nop, nodesXCoordinates } = meshData;\n const totalNodes = nodesXCoordinates.length;\n const nodesPerElement = nop[0].length;\n\n // Initialize arrays\n const nodeNeighbors = Array.from({ length: totalNodes }, () => []);\n const neighborCount = Array(totalNodes).fill(0);\n\n // Loop through all elements\n for (let elemIndex = 0; elemIndex < nop.length; elemIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) {\n const nodeIndex = nop[elemIndex][localNodeIndex] - 1;\n\n // Increment the total number of neighboring elements for this node\n neighborCount[nodeIndex] = neighborCount[nodeIndex] + 1;\n\n // Store the element index as a neighbor of this node\n nodeNeighbors[nodeIndex].push(elemIndex);\n }\n }\n\n return { nodeNeighbors, neighborCount };\n}\n\n/**\n * Function to extracts boundary line segments for ray casting\n * @param {object} meshData - Object containing mesh data\n * @returns {array} Array of segments\n */\nexport function getBoundarySegments(meshData) {\n let boundaryLineElements = [];\n let boundaryNodesSegments = [];\n let boundaryGlobalElementIndex = 0;\n let boundarySides;\n const { nodesXCoordinates, nodesYCoordinates, nop, boundaryElements, meshDimension, elementOrder } =\n meshData;\n\n if (meshDimension === \"1D\") {\n if (elementOrder === \"linear\") {\n 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 } else if (elementOrder === \"quadratic\") {\n 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 } else if (meshDimension === \"2D\") {\n if (elementOrder === \"linear\") {\n 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 } else if (elementOrder === \"quadratic\") {\n 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 }\n\n // Iterate over all boundaries\n for (let boundaryIndex = 0; boundaryIndex < boundaryElements.length; boundaryIndex++) {\n // Iterate over all elements in the current boundary\n for (\n let boundaryLocalElementIndex = 0;\n boundaryLocalElementIndex < boundaryElements[boundaryIndex].length;\n boundaryLocalElementIndex++\n ) {\n boundaryLineElements[boundaryGlobalElementIndex] =\n boundaryElements[boundaryIndex][boundaryLocalElementIndex];\n boundaryGlobalElementIndex++;\n // Retrieve the element index and the side\n const [elementIndex, side] = boundaryElements[boundaryIndex][boundaryLocalElementIndex];\n let boundaryLocalNodeIndices = boundarySides[side];\n let currentElementNodesX = [];\n let currentElementNodesY = [];\n\n for (\n let boundaryLocalNodeIndex = 0;\n boundaryLocalNodeIndex < boundaryLocalNodeIndices.length;\n boundaryLocalNodeIndex++\n ) {\n const globalNodeIndex = nop[elementIndex][boundaryLocalNodeIndices[boundaryLocalNodeIndex]] - 1;\n\n currentElementNodesX.push(nodesXCoordinates[globalNodeIndex]);\n currentElementNodesY.push(nodesYCoordinates[globalNodeIndex]);\n }\n\n // Create segments for this element\n for (let k = 0; k < currentElementNodesX.length - 1; k++) {\n boundaryNodesSegments.push([\n [currentElementNodesX[k], currentElementNodesY[k]],\n [currentElementNodesX[k + 1], currentElementNodesY[k + 1]],\n ]);\n }\n }\n }\n return boundaryNodesSegments;\n}\n","/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 1: [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 nodesPerElement = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < nodesPerElement; 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 nodesPerElement = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < nodesPerElement; 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 nodesPerElement = this.nop[elementIndex].length;\n const localJacobianMatrix = Array(nodesPerElement)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n const localResidualVector = Array(nodesPerElement).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 ([boundaryElementIndex, _]) => boundaryElementIndex === 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 < nodesPerElement; 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 nodesPerElement = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < nodesPerElement; 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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 nodesPerElement,\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 < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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, nodesPerElement } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(nodesPerElement)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n const localResidualVector = Array(nodesPerElement).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(nodesPerElement);\n const localToGlobalMap = Array(nodesPerElement);\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; 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 nodesPerElement,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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 nodesPerElement,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 1: [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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 nodesPerElement,\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 < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; 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 < nodesPerElement; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; 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 < nodesPerElement; 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 < nodesPerElement; 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, nodesPerElement } = 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(nodesPerElement)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n const localResidualVector = Array(nodesPerElement).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(nodesPerElement);\n const localToGlobalMap = Array(nodesPerElement);\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; 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 < nodesPerElement; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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 nodesPerElement,\n });\n\n // Calculate solution derivatives\n let solutionDerivX = 0;\n let solutionDerivY = 0;\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; 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 < nodesPerElement; 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 < nodesPerElement; 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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { initializeFEA } from \"../mesh/meshUtilsScript.js\";\nimport { assembleHeatConductionFront } from \"../models/heatConductionScript.js\";\nimport { ThermalBoundaryConditions } from \"../models/thermalBoundaryConditionsScript.js\";\nimport { assembleFrontPropagationFront } from \"../models/frontPropagationScript.js\";\nimport { GenericBoundaryConditions } from \"../models/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 nodesPerElement = FEAData.nodesPerElement;\n\n // Calculate required array sizes\n initializeFrontalArrays(nodesPerElement, 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.nodesPerElement; 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.nodesPerElement;\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} nodesPerElement - Number of nodes per element\n * @param {number} numElements - Number of elements in the mesh\n */\nfunction initializeFrontalArrays(nodesPerElement, numElements) {\n // Use the actual number of elements from the mesh\n frontalData.nodalNumbering = Array(numElements)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n frontalData.nodeConstraintCode = Array(nodesPerElement).fill(0);\n frontalData.boundaryValues = Array(nodesPerElement).fill(0);\n frontalData.globalResidualVector = Array(nodesPerElement).fill(0);\n frontalData.solutionVector = Array(nodesPerElement).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 = nodesPerElement;\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(nodesPerElement, 2000);\n frontalState.globalSolutionVector = Array(systemSize).fill(0);\n frontalState.frontDataIndex = 0;\n\n // Initialize elementData arrays\n elementData.localJacobianMatrix = Array(nodesPerElement)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n elementData.currentElementIndex = 0;\n\n // Initialize frontStorage arrays\n const frontSize = estimateFrontSize(nodesPerElement, 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} nodesPerElement - 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(nodesPerElement, numElements) {\n const frontWidthEstimate = Math.max(Math.ceil(Math.sqrt(numElements)) * nodesPerElement, nodesPerElement * 2);\n return frontWidthEstimate * numElements;\n}\n// Old function to estimate the required front size\n// function estimateFrontSize(nodesPerElement, numElements, nodesPerElement) {\n// const frontWidthEstimate = Math.ceil(Math.sqrt(numElements) * nodesPerElement * 2);\n// const frontSize = frontWidthEstimate * nodesPerElement * 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.nodesPerElement)\n .fill()\n .map(() => Array(FEAData.nodesPerElement).fill(0));\n let boundaryResidualVector = Array(FEAData.nodesPerElement).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(([boundaryElementIndex, _]) => boundaryElementIndex === 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.nodesPerElement; localNodeI++) {\n for (let localNodeJ = 0; localNodeJ < FEAData.nodesPerElement; 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.nodesPerElement; 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 nodesPerElement = meshData.nodesXCoordinates.length;\n const systemSize = Math.max(nodesPerElement, frontalState.globalSolutionVector.length);\n let localDestination = Array(FEAData.nodesPerElement).fill(0);\n let rowDestination = Array(FEAData.nodesPerElement).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(nodesPerElement).fill(0);\n let columnSwapCount = Array(nodesPerElement).fill(0);\n let lastAppearanceCheck = Array(nodesPerElement).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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 \"../models/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 * @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 = {}) {\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 // Extract context\n const { maxIterations = 100, tolerance = 1e-4 } = context;\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport {\n prepareMesh,\n pointInsideTriangle,\n pointInsideQuadrilateral,\n computeNodeNeighbors,\n getBoundarySegments,\n} from \"../mesh/meshUtilsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { initializeFEA } from \"../mesh/meshUtilsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to create plots of the solution vector\n * @param {object} result - Object containing solution vector and mesh information\n * @param {object} model - Object containing model properties\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n */\nexport function plotSolution(model, result, plotType, plotDivId) {\n const { nodesXCoordinates, nodesYCoordinates } = result.nodesCoordinates;\n const solutionVector = result.solutionVector;\n const solverConfig = model.solverConfig;\n const meshDimension = model.meshConfig.meshDimension;\n const meshData = prepareMesh(model.meshConfig); // Retrieve mesh connectivity details (used in splitQuadrilateral)\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: nodesXCoordinates,\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 plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = 300;\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: 50, r: 50, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Check if solutionVector is a nested array\n let zData;\n if (Array.isArray(solutionVector[0])) {\n zData = solutionVector.map((val) => val[0]);\n } else {\n zData = solutionVector;\n }\n\n // Plot sizing parameters\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;\n\n // 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 // Create the plot\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zData,\n type: \"contour\",\n line: {\n smoothing: 0.85,\n },\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 Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n}\n\n/**\n * Function to generate a dense visualization grid and interpolate the FEM solution on it\n * @param {object} result - Object containing solution vector and mesh information\n * @param {object} model - Object containing model properties\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n */\nexport function plotInterpolatedSolution(model, result, plotType, plotDivId) {\n const { nodesXCoordinates, nodesYCoordinates } = result.nodesCoordinates; // TODO: Check if we should place it inside the 2D block\n const meshDimension = model.meshConfig.meshDimension;\n const meshData = prepareMesh(model.meshConfig); // Retrieve mesh connectivity details\n\n // Initialize BasisFunctions once here to avoid creating it inside the loop\n const basisFunctions = new BasisFunctions({\n meshDimension: model.meshConfig.meshDimension,\n elementOrder: model.meshConfig.elementOrder,\n });\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // 1D plot region\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n const visNodeXCoordinates = [];\n const visNodeYCoordinates = [];\n let visSolution = [];\n const visNodesX = 1e2; // Number of nodes along the x-axis of the visualization grid\n const visNodesY = 1e2; // Number of nodes along the y-axis of the visualization grid\n\n // const { nodesXCoordinates, nodesYCoordinates } = result.nodesCoordinates;\n const deltavisX = (Math.max(...nodesXCoordinates) - Math.min(...nodesXCoordinates)) / (visNodesX - 1);\n const deltavisY = (Math.max(...nodesYCoordinates) - Math.min(...nodesYCoordinates)) / (visNodesY - 1);\n\n visNodeXCoordinates[0] = Math.min(...nodesXCoordinates);\n visNodeYCoordinates[0] = Math.min(...nodesYCoordinates);\n\n for (let visNodeIndexY = 1; visNodeIndexY < visNodesY; visNodeIndexY++) {\n visNodeXCoordinates[visNodeIndexY] = visNodeXCoordinates[0];\n visNodeYCoordinates[visNodeIndexY] = visNodeYCoordinates[0] + visNodeIndexY * deltavisY;\n }\n\n for (let visNodeIndexX = 1; visNodeIndexX < visNodesX; visNodeIndexX++) {\n const nnode = visNodeIndexX * visNodesY;\n visNodeXCoordinates[nnode] = visNodeXCoordinates[0] + visNodeIndexX * deltavisX;\n visNodeYCoordinates[nnode] = visNodeYCoordinates[0];\n\n for (let visNodeIndexY = 1; visNodeIndexY < visNodesY; visNodeIndexY++) {\n visNodeXCoordinates[nnode + visNodeIndexY] = visNodeXCoordinates[nnode];\n visNodeYCoordinates[nnode + visNodeIndexY] = visNodeYCoordinates[nnode] + visNodeIndexY * deltavisY;\n }\n }\n\n const visNodeCoordinates = { visNodeXCoordinates, visNodeYCoordinates };\n\n // Initialize visSolution with null for all visualization nodes\n visSolution = new Array(visNodesX * visNodesY).fill(null);\n\n // Get boundary segments for ray casting\n const boundarySegments = getBoundarySegments(meshData);\n\n // Perform adjacency-based search to find which element contains a given point (quick search)\n const { nodeNeighbors, neighborCount } = computeNodeNeighbors(meshData);\n let lastParentElement = 0;\n for (let visNodeIndex = 0; visNodeIndex < visNodesX * visNodesY; visNodeIndex++) {\n // Ray casting check\n if (\n !pointInsidePolygon(\n visNodeXCoordinates[visNodeIndex],\n visNodeYCoordinates[visNodeIndex],\n boundarySegments\n )\n ) {\n continue;\n }\n let found = false;\n for (\n let localNodeIndex = 0;\n localNodeIndex < meshData.nop[lastParentElement].length;\n localNodeIndex++\n ) {\n let globalNodeIndex = meshData.nop[lastParentElement][localNodeIndex] - 1;\n for (\n let neighborElementsIndex = 0;\n neighborElementsIndex < neighborCount[globalNodeIndex];\n neighborElementsIndex++\n ) {\n let currentElement = nodeNeighbors[globalNodeIndex][neighborElementsIndex];\n const searchResult = pointSearch(\n model,\n meshData,\n result,\n currentElement,\n visNodeXCoordinates[visNodeIndex],\n visNodeYCoordinates[visNodeIndex],\n basisFunctions\n );\n\n if (searchResult.inside) {\n lastParentElement = currentElement;\n visSolution[visNodeIndex] = searchResult.value;\n found = true;\n break;\n }\n }\n if (found) break;\n }\n\n // Scan all elements to find which element contains a given point (slow search)\n if (!found) {\n for (let currentElement = 0; currentElement < meshData.nop.length; currentElement++) {\n const searchResult = pointSearch(\n model,\n meshData,\n result,\n currentElement,\n visNodeXCoordinates[visNodeIndex],\n visNodeYCoordinates[visNodeIndex],\n basisFunctions\n );\n\n if (searchResult.inside) {\n lastParentElement = currentElement;\n visSolution[visNodeIndex] = searchResult.value;\n found = true;\n break;\n }\n }\n }\n }\n\n // Plot sizing parameters\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;\n\n // Layout properties\n let layout = {\n title: `${plotType} plot (interpolated) - ${model.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 // Create the plot\n let contourData = {\n x: visNodeXCoordinates,\n y: visNodeYCoordinates,\n z: visSolution,\n type: \"contour\",\n line: {\n smoothing: 0.85,\n },\n contours: {\n coloring: \"heatmap\",\n showlabels: false,\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: \"Solution\",\n },\n name: \"Interpolated Solution Field\",\n };\n\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n}\n\n/**\n * Function to search if a point is inside an element and interpolate the solution\n * @param {object} model - Object containing model properties\n * @param {object} meshData - Object containing mesh data\n * @param {object} result - Object containing solution vector and mesh information\n * @param {number} currentElement - Index of the element to check\n * @param {number} visNodeXCoordinate - X-coordinate of the point\n * @param {number} visNodeYCoordinate - Y-coordinate of the point\n * @param {object} basisFunctions - Instance of BasisFunctions class\n * @returns {object} Object containing inside boolean and interpolated value\n */\nfunction pointSearch(model, meshData, result, currentElement, visNodeXCoordinate, visNodeYCoordinate, basisFunctions) {\n const { nodesXCoordinates, nodesYCoordinates } = result.nodesCoordinates;\n const nodesPerElement = meshData.nop[currentElement].length;\n\n if (nodesPerElement === 4) {\n // Linear quadrilateral element\n let vertices = [\n [\n nodesXCoordinates[meshData.nop[currentElement][0] - 1],\n nodesYCoordinates[meshData.nop[currentElement][0] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][1] - 1],\n nodesYCoordinates[meshData.nop[currentElement][1] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][2] - 1],\n nodesYCoordinates[meshData.nop[currentElement][2] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][3] - 1],\n nodesYCoordinates[meshData.nop[currentElement][3] - 1],\n ],\n ];\n const pointCheck = pointInsideQuadrilateral(visNodeXCoordinate, visNodeYCoordinate, vertices);\n if (pointCheck.inside) {\n return {\n inside: true,\n value: solutionInterpolation(model, meshData, result, currentElement, pointCheck.ksi, pointCheck.eta, basisFunctions),\n };\n }\n } else if (nodesPerElement === 9) {\n // Quadratic quadrilateral element\n let vertices = [\n [\n nodesXCoordinates[meshData.nop[currentElement][0] - 1],\n nodesYCoordinates[meshData.nop[currentElement][0] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][2] - 1],\n nodesYCoordinates[meshData.nop[currentElement][2] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][6] - 1],\n nodesYCoordinates[meshData.nop[currentElement][6] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][8] - 1],\n nodesYCoordinates[meshData.nop[currentElement][8] - 1],\n ],\n ];\n const pointCheck = pointInsideQuadrilateral(visNodeXCoordinate, visNodeYCoordinate, vertices);\n if (pointCheck.inside) {\n return {\n inside: true,\n value: solutionInterpolation(model, meshData, result, currentElement, pointCheck.ksi, pointCheck.eta, basisFunctions),\n };\n }\n } // TODO: Add also triangular element cases\n return { inside: false, value: null };\n}\n\n/**\n * Function to interpolate the solution at a specific point (ksi, eta) within an element\n * @param {object} model - Object containing model properties\n * @param {object} meshData - Object containing mesh data\n * @param {object} result - Object containing solution vector and mesh information\n * @param {number} elementIndex - Index of the element containing the point\n * @param {number} ksi - First natural coordinate (ksi)\n * @param {number} eta - Second natural coordinate (eta)\n * @param {object} basisFunctions - Instance of BasisFunctions class\n * @returns {number} Interpolated solution value\n */\nfunction solutionInterpolation(model, meshData, result, elementIndex, ksi, eta, basisFunctions) {\n // Initialize FEA components\n const solutionVector = result.solutionVector;\n const nodesPerElement = meshData.nop[elementIndex].length;\n\n // Get basis functions for the current point\n const basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(ksi, eta);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n\n // Check if solutionVector is a nested array\n let zData;\n if (Array.isArray(solutionVector[0])) {\n zData = solutionVector.map((val) => val[0]);\n } else {\n zData = solutionVector;\n }\n\n // Interpolate solution\n let solutionInterpolationValue = 0;\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) {\n solutionInterpolationValue +=\n zData[meshData.nop[elementIndex][localNodeIndex] - 1] * basisFunction[localNodeIndex];\n }\n\n return solutionInterpolationValue;\n}\n\n/**\n * Function to check if a point is inside a polygon using ray casting algorithm\n * @param {number} x - X-coordinate of the point\n * @param {number} y - Y-coordinate of the point\n * @param {array} segments - Array of boundary segments\n * @returns {boolean} True if the point is inside the polygon\n */\nfunction pointInsidePolygon(x, y, segments) {\n let inside = false;\n for (let i = 0; i < segments.length; i++) {\n const [[x1, y1], [x2, y2]] = segments[i];\n const intersect = y1 > y !== y2 > y && x < ((x2 - x1) * (y - y1)) / (y2 - y1) + x1;\n if (intersect) inside = !inside;\n }\n return inside;\n}\n","/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { solveLinearSystemAsync } from \"./methods/linearSystemSolverScript.js\";\nimport { prepareMesh } from \"./mesh/meshUtilsScript.js\";\nimport { assembleFrontPropagationMat } from \"./models/frontPropagationScript.js\";\nimport { assembleGeneralFormPDEMat, assembleGeneralFormPDEFront } from \"./models/generalFormPDEScript.js\";\nimport { assembleHeatConductionMat, assembleHeatConductionFront } from \"./models/heatConductionScript.js\";\nimport { runFrontalSolver } from \"./methods/frontalSolverScript.js\";\nimport { basicLog, debugLog, warnLog, 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 containifng the solution vector and 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 warnLog(\n \"FEAScript is provided “as is” without any warranty. The authors are not responsible for any damages or losses that may result from using the software. See the license for more details: https://github.com/FEAScript/FEAScript-core/blob/main/LICENSE\"\n );\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?.coefficientFunctions) {\n this.coefficientFunctions = options.coefficientFunctions;\n debugLog(\"Coefficient functions set\");\n }\n // Only update if a value is provided, otherwise keep the default\n if (options?.maxIterations !== undefined) {\n this.maxIterations = options.maxIterations;\n }\n if (options?.tolerance !== undefined) {\n this.tolerance = options.tolerance;\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 /**\n * Function to solve the finite element problem synchronously\n * @param {object} [options] - Additional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {object} An object containing the solution vector and mesh information\n */\n solve(options = {}) {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n errorLog(\"Solver config, mesh config, and boundary conditions must be set before solving.\");\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 and nodal numbering 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 basicLog(`Using solver: ${this.solverConfig}`);\n if (this.solverConfig === \"heatConductionScript\") {\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 maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n });\n solutionVector = linearSystemResult.solutionVector;\n }\n } else if (this.solverConfig === \"frontPropagationScript\") {\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 // TODO: Consider using different maxIterations/tolerance for Newton-Raphson and linear solver\n maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\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);\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 // 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 maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n });\n solutionVector = linearSystemResult.solutionVector;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n\n /**\n * Function to solve the finite element problem asynchronously\n * @param {object} computeEngine - The compute engine to use for the asynchronous solver (e.g., a worker or a WebGPU context)\n * @param {object} [options] - Additional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {Promise} A promise that resolves to an object containing the solution vector and the coordinates of the mesh nodes\n */\n async solveAsync(computeEngine, options = {}) {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n errorLog(\"Solver config, mesh config, and boundary conditions must be set before solving.\");\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n\n basicLog(\"Preparing mesh...\");\n const meshData = prepareMesh(this.meshConfig);\n basicLog(\"Mesh preparation completed\");\n const nodesCoordinates = {\n nodesXCoordinates: meshData.nodesXCoordinates,\n nodesYCoordinates: meshData.nodesYCoordinates,\n };\n\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n\n basicLog(`Using solver: ${this.solverConfig}`);\n if (this.solverConfig === \"heatConductionScript\") {\n ({ jacobianMatrix, residualVector } = assembleHeatConductionMat(meshData, this.boundaryConditions));\n\n if (this.solverMethod === \"jacobi-gpu\") {\n const { solutionVector: x } = await solveLinearSystemAsync(\n \"jacobi-gpu\",\n jacobianMatrix,\n residualVector,\n {\n computeEngine,\n maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n }\n );\n solutionVector = x;\n } else {\n // Other async solver\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 nodesPerElement,\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 < nodesPerElement; 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 nodesPerElement,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < nodesPerElement; 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 < nodesPerElement; 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 < nodesPerElement; 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, nodesPerElement } = 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(nodesPerElement)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n const localResidualVector = Array(nodesPerElement).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(nodesPerElement);\n const localToGlobalMap = Array(nodesPerElement);\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; 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 nodesPerElement,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < nodesPerElement; 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 < nodesPerElement; 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 < nodesPerElement; 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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\"; //TODO rename importGmshQuadTri to importGmsh\nexport { logSystem } from \"./utilities/loggingScript.js\";\nexport { plotSolution, plotInterpolatedSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const printVersion = \"0.2.0 (RC)\";"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","debugLog","message","console","log","basicLog","errorLog","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","value","serialized","Error","isError","name","stack","Object","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","map","fromWireValue","returnValue","parent","slice","reduce","prop","rawValue","apply","proxy","transfers","transferCache","set","transfer","undefined","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","constructor","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","Array","prototype","concat","handler","serializedValue","msg","fill","floor","random","Number","MAX_SAFE_INTEGER","join","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","jacobianMatrixSparse","math","sparse","luFactorization","slu","solutionMatrix","lusolve","squeeze","valueOf","jacobiSolverResult","A","b","x0","n","x","xNew","iter","sum","j","maxDiff","max","abs","jacobiSolver","timeEnd","async","solveLinearSystemAsync","isArray","toArray","created","computeEngine","worker","Worker","URL","document","require","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","Comlink.wrap","initialize","createDefaultComputeEngine","result","webgpuJacobiSolver","destroy","terminate","BasisFunctions","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","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elementIndex","gmshNodes","FEAScriptNodes","push","physicalPropMap","boundaryElements","fixedBoundaryElements","boundaryNodePairs","forEach","dimension","tag","nodesPair","node1","node2","foundElement","elementConnectivity","includes","side","node1Index","indexOf","node2Index","Mesh1D","super","generateMesh","nodesXCoordinates","totalNodesX","deltaX","nodeIndex","generateNodalNumbering1D","findBoundaryElements","nop","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generateNodalNumbering2D","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","prepareMesh","meshConfig","mesh","nodesCoordinatesAndNumbering","totalElements","totalNodes","initializeFEA","meshData","colIndex","basisFunctions","gaussPointsAndWeights","localToGlobalMap","nodesPerElement","performIsoparametricMapping1D","params","xCoordinates","ksiDerivX","localNodeIndex","detJacobian","basisFunctionDerivX","performIsoparametricMapping2D","yCoordinates","etaDerivX","ksiDerivY","etaDerivY","basisFunctionDerivY","pointInsideTriangle","y","vertices","v0","v1","v2","denom","inside","pointInsideQuadrilateral","firstTriangleVertices","secondTriangleVertices","v3","splitQuadrilateral","pointInsideFirstTriangle","pointInsideSecondTriangle","getDistanceFromLine","p1","p2","distLeft","distRight","distBottom","ThermalBoundaryConditions","boundaryConditions","imposeConstantTempBoundaryConditions","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","localResidualVector","boundaryElement","find","boundaryElementIndex","_","assembleHeatConductionMat","FEAData","gaussPointIndex1","mappingResult","localNodeIndex1","localToGlobalMap1","localToGlobalMap2","gaussPointIndex2","thermalBoundaryConditions","assembleHeatConductionFront","ngl","globalIndex","GenericBoundaryConditions","imposeDirichletBoundaryConditions","imposeConstantValueBoundaryConditionsFront","assembleFrontPropagationMat","eikonalActivationFlag","eikonalViscousTerm","solutionDerivX","solutionDerivY","assembleFrontPropagationFront","frontalData","frontalState","elementData","currentElementIndex","frontStorage","runFrontalSolver","assembleFront","numElements","globalResidualVector","topologyData","lateralData","writeFlag","transformationFlag","determinant","systemSize","globalSolutionVector","frontDataIndex","frontSize","frontWidthEstimate","ceil","estimateFrontSize","frontValues","columnHeaders","pivotRow","pivotData","initializeFrontalArrays","dirichletBoundaryConditionsHandler","currentSolutionVector","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","nodesCoordinates","boundaryLocalJacobianMatrix","boundaryResidualVector","isOnRobinTypeBoundary","some","localNodeI","localNodeJ","iterationIndex","accumulatedValue","newtonRaphson","assembleMat","context","errorNorm","initialSolution","pointSearch","model","visNodeXCoordinate","visNodeYCoordinate","pointCheck","solutionInterpolation","zData","solutionInterpolationValue","pointInsidePolygon","segments","x1","y1","x2","y2","solverConfig","coefficientFunctions","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","eikonalExteralIterations","newtonRaphsonResult","B","C","D","xCoord","a","d","globalNodeIndex1","assembleGeneralFormPDEMat","solveAsync","feaWorker","isReady","_initWorker","onerror","event","workerWrapper","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","toFixed","getModelInfo","ping","file","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","numNodes","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","parseInt","replace","parametric","nodeTag","nodeIndices","idx","physicalTag","boundaryNodes","nodes","level","plotType","plotDivId","visNodeXCoordinates","visNodeYCoordinates","visSolution","visNodesX","visNodesY","deltavisX","min","deltavisY","visNodeIndexY","visNodeIndexX","boundarySegments","boundarySides","boundaryLineElements","boundaryNodesSegments","boundaryGlobalElementIndex","boundaryIndex","boundaryLocalElementIndex","boundaryLocalNodeIndices","currentElementNodesX","currentElementNodesY","boundaryLocalNodeIndex","k","getBoundarySegments","nodeNeighbors","neighborCount","from","elemIndex","computeNodeNeighbors","lastParentElement","visNodeIndex","found","neighborElementsIndex","searchResult","maxWindowWidth","window","innerWidth","aspectRatio","plotWidth","plotHeight","layout","title","width","height","xaxis","yaxis","margin","l","t","hovermode","contourData","z","smoothing","contours","coloring","showlabels","colorbar","Plotly","newPlot","responsive","yData","lineData","mode","color"],"mappings":"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"} diff --git a/dist/feascript.esm.js b/dist/feascript.esm.js index f36b4b0..4ad8d8c 100644 --- a/dist/feascript.esm.js +++ b/dist/feascript.esm.js @@ -4,5 +4,5 @@ function e(e){let t=0;for(let n=0;n"object"==typeof e&&null!==e||"function"==typeof e,m=new Map([["proxy",{canHandle:e=>u(e)&&e[r],serialize(e){const{port1:t,port2:n}=new MessageChannel;return h(e,t),[n,[n]]},deserialize:e=>(e.start(),p(e))}],["throw",{canHandle:e=>u(e)&&c 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 h(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:a,path:l}=Object.assign({path:[]},s.data),u=(s.data.argumentList||[]).map(D);let m;try{const t=l.slice(0,-1).reduce(((e,t)=>e[t]),e),n=l.reduce(((e,t)=>e[t]),e);switch(a){case"GET":m=n;break;case"SET":t[l.slice(-1)[0]]=D(s.data.value),m=!0;break;case"APPLY":m=n.apply(t,u);break;case"CONSTRUCT":m=function(e){return Object.assign(e,{[r]:!0})}(new n(...u));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;h(e,n),m=function(e,t){return M.set(e,t),e}(t,[t])}break;case"RELEASE":m=void 0;break;default:return}}catch(e){m={value:e,[c]:0}}Promise.resolve(m).catch((e=>({value:e,[c]:0}))).then((n=>{const[s,r]=$(n);t.postMessage(Object.assign(Object.assign({},s),{id:i}),r),"RELEASE"===a&&(t.removeEventListener("message",o),f(t),d in e&&"function"==typeof e[d]&&e[d]())})).catch((e=>{const[n,o]=$({value:new TypeError("Unserializable return value"),[c]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),o)}))})),t.start&&t.start()}function f(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function p(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)}})),v(e,n,[],t)}function b(e){if(e)throw new Error("Proxy has been released and is not useable")}function g(e){return F(e,new Map,{type:"RELEASE"}).then((()=>{f(e)}))}const y=new WeakMap,E="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(y.get(e)||0)-1;y.set(e,t),0===t&&g(e)}));function v(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(b(s),r===l)return()=>{!function(e){E&&E.unregister(e)}(i),g(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=F(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(D);return o.then.bind(o)}return v(e,t,[...n,r])},set(o,i,r){b(s);const[a,l]=$(r);return F(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(D)},apply(o,i,r){b(s);const l=n[n.length-1];if(l===a)return F(e,t,{type:"ENDPOINT"}).then(D);if("bind"===l)return v(e,t,n.slice(0,-1));const[d,c]=C(r);return F(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:d},c).then(D)},construct(o,i){b(s);const[r,a]=C(i);return F(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(D)}});return function(e,t){const n=(y.get(t)||0)+1;y.set(t,n),E&&E.register(e,t,e)}(i,e),i}function C(e){const t=e.map($);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const M=new WeakMap;function $(e){for(const[t,n]of m)if(n.canHandle(e)){const[o,s]=n.serialize(e);return[{type:"HANDLER",name:t,value:o},s]}return[{type:"RAW",value:e},M.get(e)||[]]}function D(e){switch(e.type){case"HANDLER":return m.get(e.name).deserialize(e.value);case"RAW":return e.value}}function F(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)}))}function x(e,t,n,r={}){const{maxIterations:a=1e4,tolerance:l=1e-4}=r;let d=[],c=!0,u=0;if(s(`Solving system using ${e}...`),console.time("systemSolving"),"lusolve"===e){const e=math.sparse(t),o=math.slu(e,1,1);let s=math.lusolve(o,n);d=math.squeeze(s).valueOf()}else if("jacobi"===e){const e=function(e,t,n,o={}){const{maxIterations:s,tolerance:i}=o,r=e.length;let a=[...n],l=new Array(r);for(let n=0;n{}))),m.worker.terminate()),{solutionVector:f,converged:b,iterations:u}}class w{constructor({meshDimension:e,elementOrder:t}){this.meshDimension=e,this.elementOrder=t}getBasisFunctions(e,t=null){let n=[],o=[],s=[];if("1D"===this.meshDimension)"linear"===this.elementOrder?(n[0]=1-e,n[1]=e,o[0]=-1,o[1]=1):"quadratic"===this.elementOrder&&(n[0]=1-3*e+2*e**2,n[1]=4*e-4*e**2,n[2]=2*e**2-e,o[0]=4*e-3,o[1]=4-8*e,o[2]=4*e-1);else if("2D"===this.meshDimension){if(null===t)return void i("Eta coordinate is required for 2D elements");if("linear"===this.elementOrder){function r(e){return 1-e}n[0]=r(e)*r(t),n[1]=r(e)*t,n[2]=e*r(t),n[3]=e*t,o[0]=-1*r(t),o[1]=-1*t,o[2]=1*r(t),o[3]=1*t,s[0]=-1*r(e),s[1]=1*r(e),s[2]=-1*e,s[3]=1*e}else if("quadratic"===this.elementOrder){function a(e){return 2*e**2-3*e+1}function l(e){return-4*e**2+4*e}function d(e){return 2*e**2-e}function c(e){return 4*e-3}function u(e){return-8*e+4}function m(e){return 4*e-1}n[0]=a(e)*a(t),n[1]=a(e)*l(t),n[2]=a(e)*d(t),n[3]=l(e)*a(t),n[4]=l(e)*l(t),n[5]=l(e)*d(t),n[6]=d(e)*a(t),n[7]=d(e)*l(t),n[8]=d(e)*d(t),o[0]=c(e)*a(t),o[1]=c(e)*l(t),o[2]=c(e)*d(t),o[3]=u(e)*a(t),o[4]=u(e)*l(t),o[5]=u(e)*d(t),o[6]=m(e)*a(t),o[7]=m(e)*l(t),o[8]=m(e)*d(t),s[0]=a(e)*c(t),s[1]=a(e)*u(t),s[2]=a(e)*m(t),s[3]=l(e)*c(t),s[4]=l(e)*u(t),s[5]=l(e)*m(t),s[6]=d(e)*c(t),s[7]=d(e)*u(t),s[8]=d(e)*m(t)}}return{basisFunction:n,basisFunctionDerivKsi:o,basisFunctionDerivEta:s}}}class N{constructor({numElementsX:e=null,maxX:t=null,numElementsY:n=null,maxY:o=null,meshDimension:i=null,elementOrder:r="linear",parsedMesh:a=null}){this.numElementsX=e,this.numElementsY=n,this.maxX=t,this.maxY=o,this.meshDimension=i,this.elementOrder=r,this.parsedMesh=a,this.boundaryElementsProcessed=!1,this.parsedMesh&&(s("Using pre-parsed mesh from gmshReader data for mesh generation."),this.parseMeshFromGmsh())}parseMeshFromGmsh(){if(this.parsedMesh.nodalNumbering||i("No valid nodal numbering found in the parsed mesh."),"object"==typeof this.parsedMesh.nodalNumbering&&!Array.isArray(this.parsedMesh.nodalNumbering)){const e=this.parsedMesh.nodalNumbering.quadElements||[];if(this.parsedMesh.nodalNumbering.triangleElements,o("Initial parsed mesh nodal numbering from GMSH format: "+JSON.stringify(this.parsedMesh.nodalNumbering)),this.parsedMesh.elementTypes[3]||this.parsedMesh.elementTypes[10]){const t=[];for(let n=0;n0&&void 0===this.parsedMesh.boundaryElements[0]){const e=[];for(let t=1;t{if(1===e.dimension){const t=this.parsedMesh.boundaryNodePairs[e.tag]||[];t.length>0&&(this.parsedMesh.boundaryElements[e.tag]||(this.parsedMesh.boundaryElements[e.tag]=[]),t.forEach((t=>{const n=t[0],s=t[1];o(`Processing boundary node pair: [${n}, ${s}] for boundary ${e.tag} (${e.name||"unnamed"})`);let r=!1;for(let t=0;t0&&void 0===this.parsedMesh.boundaryElements[0])){const e=[];for(let t=1;t{if("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((c=>{if("convection"===this.boundaryConditions[c][0]){const u=l[c],m=d[c];o(`Boundary ${c}: Applying convection with heat transfer coefficient h=${u} W/(m²·K) and external temperature T∞=${m} K`),this.boundaryElements[c].forEach((([l,d])=>{if("linear"===this.elementOrder){let c,h,f,p,b;0===d?(c=n[0],h=0,f=0,p=3,b=2):1===d?(c=0,h=n[0],f=0,p=2,b=1):2===d?(c=n[0],h=1,f=1,p=4,b=2):3===d&&(c=1,h=n[0],f=2,p=4,b=1);let g=a.getBasisFunctions(c,h),y=g.basisFunction,E=g.basisFunctionDerivKsi,v=g.basisFunctionDerivEta,C=0,M=0,$=0,D=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,c=Array(d).fill().map((()=>Array(d).fill(0))),u=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})`),u[t]+=-h*f,c[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 g=r.getBasisFunctions(o,l),y=g.basisFunction,E=g.basisFunctionDerivKsi,v=g.basisFunctionDerivEta;let C,M=0,$=0,D=0,F=0;for(let o=0;oArray(a).fill(0))),m=Array(a).fill(0),h=Array(a),f=Array(a);for(let n=0;ne-1)),{detJacobian:f,basisFunctionDerivX:p,basisFunctionDerivY:b}=I({basisFunction:n,basisFunctionDerivKsi:s,basisFunctionDerivEta:c,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 j(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:c,totalElements:u,meshDimension:m,elementOrder:h}=e,f=k(e),{residualVector:p,jacobianMatrix:b,localToGlobalMap:g,basisFunctions:y,gaussPoints:E,gaussWeights:v,numNodes:C}=f;for(let e=0;eArray(d).fill(0))),p=Array(d).fill(0),b=Array(d),g=Array(d);for(let n=0;nArray(e).fill(0))),W.nodeConstraintCode=Array(e).fill(0),W.boundaryValues=Array(e).fill(0),W.globalResidualVector=Array(e).fill(0),W.solutionVector=Array(e).fill(0),W.topologyData=Array(t).fill(0),W.lateralData=Array(t).fill(0),G.writeFlag=0,G.totalNodes=e,G.transformationFlag=0,G.nodesPerElement=Array(t).fill(0),G.determinant=1;const n=Math.max(e,2e3);G.globalSolutionVector=Array(n).fill(0),G.frontDataIndex=0,K.localJacobianMatrix=Array(e).fill().map((()=>Array(e).fill(0))),K.currentElementIndex=0;const o=function(e,t){const n=Math.max(Math.ceil(Math.sqrt(t))*e,2*e);return n*t}(e,t);J.frontValues=Array(o).fill(0),J.columnHeaders=Array(n).fill(0),J.pivotRow=Array(n).fill(0),J.pivotData=Array(o).fill(0)}(a.numNodes,d),s("Solving system using frontal..."),console.time("systemSolving"),H=new w({meshDimension:t.meshDimension,elementOrder:t.elementOrder});for(let e=0;eArray(l).fill(0))),y=Array(a).fill(0),E=Array(a).fill(0),v=Array(a).fill(0),C=1;G.writeFlag++;let M=1,$=1;K.currentElementIndex=0;for(let e=0;el||D>l)return void i("Error: systemSize not large enough");for(let e=0;e0)for(let e=0;e$||K.currentElementIndexMath.abs(n)&&(n=r,t=s,e=i)}}}let s=Math.abs(m[e-1]);d=Math.abs(J.columnHeaders[t-1]);let a=s+d+y[s-1]+E[d-1];G.determinant=G.determinant*n*(-1)**a/Math.abs(n);for(let e=0;e=s&&y[e]--,e>=d&&E[e]--;if(Math.abs(n)<1e-10&&i(`Matrix singular or ill-conditioned, currentElementIndex=${K.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||K.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:W.nodalNumbering,meshData:e,basisFunctions:H,FEAData:t,solutionVector:G.currentSolutionVector,eikonalActivationFlag:G.eikonalActivationFlag});let d=Array(t.numNodes).fill().map((()=>Array(t.numNodes).fill(0))),c=Array(t.numNodes).fill(0);if(o===Y){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,H);d=r.localJacobianMatrix,c=r.localResidualVector}}for(let e=0;e0)continue;let r=0;J.pivotRow[s-1]=0;for(let e=0;e100){i(`Solution not converged. Error norm: ${o}`);break}a++}return{solutionVector:d,converged:r,iterations:a,jacobianMatrix:c,residualVector:u}}class Q{constructor(){var e;this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",this.coefficientFunctions=null,e="FEAScript is provided “as is” without any warranty. The authors are not responsible for any damages or losses that may result from using the software. See the license for more details: https://github.com/FEAScript/FEAScript-core/blob/main/LICENSE",console.log("%c[WARN] "+e,"color: #FF9800; font-weight: bold;"),s("FEAScriptModel instance created")}setSolverConfig(e,t={}){this.solverConfig=e,t?.coefficientFunctions&&(this.coefficientFunctions=t.coefficientFunctions,o("Coefficient functions set")),void 0!==t?.maxIterations&&(this.maxIterations=t.maxIterations),void 0!==t?.tolerance&&(this.tolerance=t.tolerance),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(e={}){this.solverConfig&&this.meshConfig&&this.boundaryConditions||i("Solver config, mesh config, and boundary conditions must be set before solving.");let t=[],n=[],o=[],r=[];s("Preparing mesh...");const a=V(this.meshConfig);s("Mesh preparation completed");const l={nodesXCoordinates:a.nodesXCoordinates,nodesYCoordinates:a.nodesYCoordinates};if(s("Beginning solving process..."),console.time("totalSolvingTime"),s(`Using solver: ${this.solverConfig}`),"heatConductionScript"===this.solverConfig)if("frontal"===this.solverMethod){o=L(Y,a,this.boundaryConditions).solutionVector}else{({jacobianMatrix:t,residualVector:n}=P(a,this.boundaryConditions));o=x(this.solverMethod,t,n,{maxIterations:e.maxIterations??this.maxIterations,tolerance:e.tolerance??this.tolerance}).solutionVector}else if("frontPropagationScript"===this.solverConfig){let s=0;const i=5,l={meshData:a,boundaryConditions:this.boundaryConditions,eikonalActivationFlag:s,solverMethod:this.solverMethod,initialSolution:r,maxIterations:e.maxIterations??this.maxIterations,tolerance:e.tolerance??this.tolerance};for(;s<=1;){l.eikonalActivationFlag=s,o.length>0&&(l.initialSolution=[...o]);const e=_(j,l);t=e.jacobianMatrix,n=e.residualVector,o=e.solutionVector,s+=1/i}}else if("generalFormPDEScript"===this.solverConfig)if("frontal"===this.solverMethod)i("Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.");else{({jacobianMatrix:t,residualVector:n}=function(e,t,n){s("Starting general form PDE matrix assembly...");const{nodesXCoordinates:o,nodesYCoordinates:r,nop:a,boundaryElements:l,totalElements:d,meshDimension:c,elementOrder:u}=e,{A:m,B:h,C:f,D:p}=n,b=k(e),{residualVector:g,jacobianMatrix:y,localToGlobalMap:E,basisFunctions:v,gaussPoints:C,gaussWeights:M,numNodes:$}=b;if("1D"===c)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},c=0,u=[],m=0,h=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},b=0,g={};for(;i""!==e));if("meshFormat"===s)t.gmshV=parseFloat(o[0]),t.ascii="0"===o[1],t.fltBytes=o[2];else if("physicalNames"===s){if(o.length>=3){if(!/^\d+$/.test(o[0])){i++;continue}const e=parseInt(o[0],10),n=parseInt(o[1],10);let s=o.slice(2).join(" ");s=s.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:n,dimension:e,name:s})}}else if("nodes"===s){if(0===r){r=parseInt(o[0],10),a=parseInt(o[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;g[n]||(g[n]=[]),g[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);b++,b===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=g[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),o(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t};function ee(e,t,n,o,s,i){const{nodesXCoordinates:r,nodesYCoordinates:a}=t;if("1D"===o&&"line"===s){let t;t=e.length>0&&Array.isArray(e[0])?e.map((e=>e[0])):e,Array.from(r);let o={x:r,y:t,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},s=Math.min(window.innerWidth,700),a={title:`line plot - ${n}`,width:Math.min(s,600),height:350,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:50,r:50,t:50,b:50}};Plotly.newPlot(i,[o],a,{responsive:!0})}else if("2D"===o&&"contour"===s){let t;t=Array.isArray(e[0])?e.map((e=>e[0])):e;let o=Math.min(window.innerWidth,700),l=Math.max(...r),d=Math.max(...a)/l,c=Math.min(o,600),u={title:`${s} plot - ${n}`,width:c,height:c*d,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"},m={x:r,y:a,z:t,type:"contour",line:{smoothing:.85},contours:{coloring:"heatmap",showlabels:!1},colorbar:{title:"Solution"},name:"Solution Field"};Plotly.newPlot(i,[m],u,{responsive:!0})}}class te{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js",import.meta.url),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=p(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const o=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(o,1e3)};o()}))}async setSolverConfig(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),s("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),s(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),s("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return s(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}}const ne="0.1.4";export{Q as FEAScriptModel,te as FEAScriptWorker,Z as importGmshQuadTri,n as logSystem,ee as plotSolution,ne as printVersion}; +const r=Symbol("Comlink.proxy"),a=Symbol("Comlink.endpoint"),l=Symbol("Comlink.releaseProxy"),d=Symbol("Comlink.finalizer"),c=Symbol("Comlink.thrown"),u=e=>"object"==typeof e&&null!==e||"function"==typeof e,m=new Map([["proxy",{canHandle:e=>u(e)&&e[r],serialize(e){const{port1:t,port2:n}=new MessageChannel;return h(e,t),[n,[n]]},deserialize:e=>(e.start(),p(e))}],["throw",{canHandle:e=>u(e)&&c 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 h(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:a,path:l}=Object.assign({path:[]},s.data),u=(s.data.argumentList||[]).map($);let m;try{const t=l.slice(0,-1).reduce(((e,t)=>e[t]),e),n=l.reduce(((e,t)=>e[t]),e);switch(a){case"GET":m=n;break;case"SET":t[l.slice(-1)[0]]=$(s.data.value),m=!0;break;case"APPLY":m=n.apply(t,u);break;case"CONSTRUCT":m=function(e){return Object.assign(e,{[r]:!0})}(new n(...u));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;h(e,n),m=function(e,t){return M.set(e,t),e}(t,[t])}break;case"RELEASE":m=void 0;break;default:return}}catch(e){m={value:e,[c]:0}}Promise.resolve(m).catch((e=>({value:e,[c]:0}))).then((n=>{const[s,r]=D(n);t.postMessage(Object.assign(Object.assign({},s),{id:i}),r),"RELEASE"===a&&(t.removeEventListener("message",o),f(t),d in e&&"function"==typeof e[d]&&e[d]())})).catch((e=>{const[n,o]=D({value:new TypeError("Unserializable return value"),[c]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),o)}))})),t.start&&t.start()}function f(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function p(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)}})),v(e,n,[],t)}function b(e){if(e)throw new Error("Proxy has been released and is not useable")}function g(e){return F(e,new Map,{type:"RELEASE"}).then((()=>{f(e)}))}const y=new WeakMap,E="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(y.get(e)||0)-1;y.set(e,t),0===t&&g(e)}));function v(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(b(s),r===l)return()=>{!function(e){E&&E.unregister(e)}(i),g(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=F(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then($);return o.then.bind(o)}return v(e,t,[...n,r])},set(o,i,r){b(s);const[a,l]=D(r);return F(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then($)},apply(o,i,r){b(s);const l=n[n.length-1];if(l===a)return F(e,t,{type:"ENDPOINT"}).then($);if("bind"===l)return v(e,t,n.slice(0,-1));const[d,c]=C(r);return F(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:d},c).then($)},construct(o,i){b(s);const[r,a]=C(i);return F(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then($)}});return function(e,t){const n=(y.get(t)||0)+1;y.set(t,n),E&&E.register(e,t,e)}(i,e),i}function C(e){const t=e.map(D);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const M=new WeakMap;function D(e){for(const[t,n]of m)if(n.canHandle(e)){const[o,s]=n.serialize(e);return[{type:"HANDLER",name:t,value:o},s]}return[{type:"RAW",value:e},M.get(e)||[]]}function $(e){switch(e.type){case"HANDLER":return m.get(e.name).deserialize(e.value);case"RAW":return e.value}}function F(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)}))}function x(e,t,n,r={}){const{maxIterations:a=1e4,tolerance:l=1e-4}=r;let d=[],c=!0,u=0;if(s(`Solving system using ${e}...`),console.time("systemSolving"),"lusolve"===e){const e=math.sparse(t),o=math.slu(e,1,1);let s=math.lusolve(o,n);d=math.squeeze(s).valueOf()}else if("jacobi"===e){const e=function(e,t,n,o={}){const{maxIterations:s,tolerance:i}=o,r=e.length;let a=[...n],l=new Array(r);for(let n=0;n{}))),m.worker.terminate()),{solutionVector:f,converged:b,iterations:u}}class w{constructor({meshDimension:e,elementOrder:t}){this.meshDimension=e,this.elementOrder=t}getBasisFunctions(e,t=null){let n=[],o=[],s=[];if("1D"===this.meshDimension)"linear"===this.elementOrder?(n[0]=1-e,n[1]=e,o[0]=-1,o[1]=1):"quadratic"===this.elementOrder&&(n[0]=1-3*e+2*e**2,n[1]=4*e-4*e**2,n[2]=2*e**2-e,o[0]=4*e-3,o[1]=4-8*e,o[2]=4*e-1);else if("2D"===this.meshDimension){if(null===t)return void i("Eta coordinate is required for 2D elements");if("linear"===this.elementOrder){function r(e){return 1-e}n[0]=r(e)*r(t),n[1]=r(e)*t,n[2]=e*r(t),n[3]=e*t,o[0]=-1*r(t),o[1]=-1*t,o[2]=1*r(t),o[3]=1*t,s[0]=-1*r(e),s[1]=1*r(e),s[2]=-1*e,s[3]=1*e}else if("quadratic"===this.elementOrder){function a(e){return 2*e**2-3*e+1}function l(e){return-4*e**2+4*e}function d(e){return 2*e**2-e}function c(e){return 4*e-3}function u(e){return-8*e+4}function m(e){return 4*e-1}n[0]=a(e)*a(t),n[1]=a(e)*l(t),n[2]=a(e)*d(t),n[3]=l(e)*a(t),n[4]=l(e)*l(t),n[5]=l(e)*d(t),n[6]=d(e)*a(t),n[7]=d(e)*l(t),n[8]=d(e)*d(t),o[0]=c(e)*a(t),o[1]=c(e)*l(t),o[2]=c(e)*d(t),o[3]=u(e)*a(t),o[4]=u(e)*l(t),o[5]=u(e)*d(t),o[6]=m(e)*a(t),o[7]=m(e)*l(t),o[8]=m(e)*d(t),s[0]=a(e)*c(t),s[1]=a(e)*u(t),s[2]=a(e)*m(t),s[3]=l(e)*c(t),s[4]=l(e)*u(t),s[5]=l(e)*m(t),s[6]=d(e)*c(t),s[7]=d(e)*u(t),s[8]=d(e)*m(t)}}return{basisFunction:n,basisFunctionDerivKsi:o,basisFunctionDerivEta:s}}}class O{constructor({numElementsX:e=null,maxX:t=null,numElementsY:n=null,maxY:o=null,meshDimension:i=null,elementOrder:r="linear",parsedMesh:a=null}){this.numElementsX=e,this.numElementsY=n,this.maxX=t,this.maxY=o,this.meshDimension=i,this.elementOrder=r,this.parsedMesh=a,this.boundaryElementsProcessed=!1,this.parsedMesh&&(s("Using pre-parsed mesh from gmshReader data for mesh generation."),this.parseMeshFromGmsh())}parseMeshFromGmsh(){if(this.parsedMesh.nodalNumbering||i("No valid nodal numbering found in the parsed mesh."),Array.isArray(this.parsedMesh.nodalNumbering))return this.boundaryElementsProcessed=!0,this.parsedMesh.boundaryElementsProcessed=!0,this.parsedMesh;if("object"==typeof this.parsedMesh.nodalNumbering&&!Array.isArray(this.parsedMesh.nodalNumbering)){const e=this.parsedMesh.nodalNumbering.quadElements||[];if(this.parsedMesh.nodalNumbering.triangleElements,o("Initial parsed mesh nodal numbering from Gmsh format: "+JSON.stringify(this.parsedMesh.nodalNumbering)),this.parsedMesh.elementTypes[3]||this.parsedMesh.elementTypes[10]){const t=[];for(let n=0;n0&&void 0===this.parsedMesh.boundaryElements[0]){const e=[];for(let t=1;t{if(1===e.dimension){const t=this.parsedMesh.boundaryNodePairs[e.tag]||[];t.length>0&&(this.parsedMesh.boundaryElements[e.tag]||(this.parsedMesh.boundaryElements[e.tag]=[]),t.forEach((t=>{const n=t[0],s=t[1];o(`Processing boundary node pair: [${n}, ${s}] for boundary ${e.tag} (${e.name||"unnamed"})`);let r=!1;for(let t=0;t0&&void 0===this.parsedMesh.boundaryElements[0])){const e=[];for(let t=1;t=-1e-12&&l>=-1e-12&&1-a-l>=-1e-12,ksi:a,eta:l}}function R(e,t,n){const[o,s]=function(e){const[t,n,o,s]=e;return[[t,n,s],[t,o,s]]}(n),i=I(e,t,o),r=I(e,t,s),a=i.inside||r.inside;let l=0,d=0;if(a){const[o,s,i,r]=n,a=(n,o)=>Math.abs((o[0]-n[0])*(n[1]-t)-(n[0]-e)*(o[1]-n[1]))/Math.sqrt((o[0]-n[0])**2+(o[1]-n[1])**2),c=a(o,s),u=a(i,r),m=a(o,i);l=c/(c+u),d=m/(m+a(s,r))}return{inside:a,ksi:l,eta:d}}class Y{constructor(e,t,n,o,s){this.boundaryConditions=e,this.boundaryElements=t,this.nop=n,this.meshDimension=o,this.elementOrder=s}imposeConstantTempBoundaryConditions(e,t){"1D"===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],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((c=>{if("convection"===this.boundaryConditions[c][0]){const u=l[c],m=d[c];o(`Boundary ${c}: Applying convection with heat transfer coefficient h=${u} W/(m²·K) and external temperature T∞=${m} K`),this.boundaryElements[c].forEach((([l,d])=>{if("linear"===this.elementOrder){let c,h,f,p,b;0===d?(c=n[0],h=0,f=0,p=3,b=2):1===d?(c=0,h=n[0],f=0,p=2,b=1):2===d?(c=n[0],h=1,f=1,p=4,b=2):3===d&&(c=1,h=n[0],f=2,p=4,b=1);let g=a.getBasisFunctions(c,h),y=g.basisFunction,E=g.basisFunctionDerivKsi,v=g.basisFunctionDerivEta,C=0,M=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,c=Array(d).fill().map((()=>Array(d).fill(0))),u=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})`),u[t]+=-h*f,c[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 g=r.getBasisFunctions(o,l),y=g.basisFunction,E=g.basisFunctionDerivKsi,v=g.basisFunctionDerivEta;let C,M=0,D=0,$=0,F=0;for(let o=0;oArray(a).fill(0))),m=Array(a).fill(0),h=Array(a),f=Array(a);for(let n=0;ne-1)),{detJacobian:f,basisFunctionDerivX:p,basisFunctionDerivY:b}=T({basisFunction:n,basisFunctionDerivKsi:s,basisFunctionDerivEta:c,nodesXCoordinates:l,nodesYCoordinates:d,localToGlobalMap:m,nodesPerElement: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 W(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:c,totalElements:u,meshDimension:m,elementOrder:h}=e,f=P(e),{residualVector:p,jacobianMatrix:b,localToGlobalMap:g,basisFunctions:y,gaussPoints:E,gaussWeights:v,nodesPerElement:C}=f;for(let e=0;eArray(d).fill(0))),p=Array(d).fill(0),b=Array(d),g=Array(d);for(let n=0;nArray(e).fill(0))),K.nodeConstraintCode=Array(e).fill(0),K.boundaryValues=Array(e).fill(0),K.globalResidualVector=Array(e).fill(0),K.solutionVector=Array(e).fill(0),K.topologyData=Array(t).fill(0),K.lateralData=Array(t).fill(0),J.writeFlag=0,J.totalNodes=e,J.transformationFlag=0,J.nodesPerElement=Array(t).fill(0),J.determinant=1;const n=Math.max(e,2e3);J.globalSolutionVector=Array(n).fill(0),J.frontDataIndex=0,H.localJacobianMatrix=Array(e).fill().map((()=>Array(e).fill(0))),H.currentElementIndex=0;const o=function(e,t){const n=Math.max(Math.ceil(Math.sqrt(t))*e,2*e);return n*t}(e,t);L.frontValues=Array(o).fill(0),L.columnHeaders=Array(n).fill(0),L.pivotRow=Array(n).fill(0),L.pivotData=Array(o).fill(0)}(a.nodesPerElement,d),s("Solving system using frontal..."),console.time("systemSolving"),z=new w({meshDimension:t.meshDimension,elementOrder:t.elementOrder});for(let e=0;eArray(l).fill(0))),y=Array(a).fill(0),E=Array(a).fill(0),v=Array(a).fill(0),C=1;J.writeFlag++;let M=1,D=1;H.currentElementIndex=0;for(let e=0;el||$>l)return void i("Error: systemSize not large enough");for(let e=0;e0)for(let e=0;eD||H.currentElementIndexMath.abs(n)&&(n=r,t=s,e=i)}}}let s=Math.abs(m[e-1]);d=Math.abs(L.columnHeaders[t-1]);let a=s+d+y[s-1]+E[d-1];J.determinant=J.determinant*n*(-1)**a/Math.abs(n);for(let e=0;e=s&&y[e]--,e>=d&&E[e]--;if(Math.abs(n)<1e-10&&i(`Matrix singular or ill-conditioned, currentElementIndex=${H.currentElementIndex}, pivotGlobalRowIndex=${s}, pivotColumnGlobalIndex=${d}, pivotValue=${n}`),0===n)return;for(let t=0;t<$;t++)L.pivotRow[t]=g[e-1][t]/n;let l=K.globalResidualVector[s-1]/n;if(K.globalResidualVector[s-1]=l,b[e-1]=n,e>1)for(let n=0;n1&&0!==o)for(let e=0;e1)for(let e=0;e1||H.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:K.nodalNumbering,meshData:e,basisFunctions:z,FEAData:t,solutionVector:J.currentSolutionVector,eikonalActivationFlag:J.eikonalActivationFlag});let d=Array(t.nodesPerElement).fill().map((()=>Array(t.nodesPerElement).fill(0))),c=Array(t.nodesPerElement).fill(0);if(o===q){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,z);d=r.localJacobianMatrix,c=r.localResidualVector}}for(let e=0;e0)continue;let r=0;L.pivotRow[s-1]=0;for(let e=0;e100){i(`Solution not converged. Error norm: ${o}`);break}a++}return{solutionVector:d,converged:r,iterations:a,jacobianMatrix:c,residualVector:u}}class ee{constructor(){var e;this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",this.coefficientFunctions=null,e="FEAScript is provided “as is” without any warranty. The authors are not responsible for any damages or losses that may result from using the software. See the license for more details: https://github.com/FEAScript/FEAScript-core/blob/main/LICENSE",console.log("%c[WARN] "+e,"color: #FF9800; font-weight: bold;"),s("FEAScriptModel instance created")}setSolverConfig(e,t={}){this.solverConfig=e,t?.coefficientFunctions&&(this.coefficientFunctions=t.coefficientFunctions,o("Coefficient functions set")),void 0!==t?.maxIterations&&(this.maxIterations=t.maxIterations),void 0!==t?.tolerance&&(this.tolerance=t.tolerance),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(e={}){this.solverConfig&&this.meshConfig&&this.boundaryConditions||i("Solver config, mesh config, and boundary conditions must be set before solving.");let t=[],n=[],o=[],r=[];s("Preparing mesh...");const a=V(this.meshConfig);s("Mesh preparation completed");const l={nodesXCoordinates:a.nodesXCoordinates,nodesYCoordinates:a.nodesYCoordinates};if(s("Beginning solving process..."),console.time("totalSolvingTime"),s(`Using solver: ${this.solverConfig}`),"heatConductionScript"===this.solverConfig)if("frontal"===this.solverMethod){o=U(q,a,this.boundaryConditions).solutionVector}else{({jacobianMatrix:t,residualVector:n}=B(a,this.boundaryConditions));o=x(this.solverMethod,t,n,{maxIterations:e.maxIterations??this.maxIterations,tolerance:e.tolerance??this.tolerance}).solutionVector}else if("frontPropagationScript"===this.solverConfig){let s=0;const i=5,l={meshData:a,boundaryConditions:this.boundaryConditions,eikonalActivationFlag:s,solverMethod:this.solverMethod,initialSolution:r,maxIterations:e.maxIterations??this.maxIterations,tolerance:e.tolerance??this.tolerance};for(;s<=1;){l.eikonalActivationFlag=s,o.length>0&&(l.initialSolution=[...o]);const e=Z(W,l);t=e.jacobianMatrix,n=e.residualVector,o=e.solutionVector,s+=1/i}}else if("generalFormPDEScript"===this.solverConfig)if("frontal"===this.solverMethod)i("Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.");else{({jacobianMatrix:t,residualVector:n}=function(e,t,n){s("Starting general form PDE matrix assembly...");const{nodesXCoordinates:o,nodesYCoordinates:r,nop:a,boundaryElements:l,totalElements:d,meshDimension:c,elementOrder:u}=e,{A:m,B:h,C:f,D:p}=n,b=P(e),{residualVector:g,jacobianMatrix:y,localToGlobalMap:E,basisFunctions:v,gaussPoints:C,gaussWeights:M,nodesPerElement:D}=b;if("1D"===c)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},c=0,u=[],m=0,h=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},b=0,g={};for(;i""!==e));if("meshFormat"===s)t.gmshV=parseFloat(o[0]),t.ascii="0"===o[1],t.fltBytes=o[2];else if("physicalNames"===s){if(o.length>=3){if(!/^\d+$/.test(o[0])){i++;continue}const e=parseInt(o[0],10),n=parseInt(o[1],10);let s=o.slice(2).join(" ");s=s.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:n,dimension:e,name:s})}}else if("nodes"===s){if(0===r){r=parseInt(o[0],10),a=parseInt(o[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;g[n]||(g[n]=[]),g[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);b++,b===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=g[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),o(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t};function ne(e,t,n,o){const{nodesXCoordinates:s,nodesYCoordinates:i}=t.nodesCoordinates,r=t.solutionVector,a=e.solverConfig,l=e.meshConfig.meshDimension;if(V(e.meshConfig),"1D"===l&&"line"===n){let e;e=r.length>0&&Array.isArray(r[0])?r.map((e=>e[0])):r,Array.from(s);let t={x:s,y:e,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},n=Math.min(window.innerWidth,700),i={title:`line plot - ${a}`,width:Math.min(n,600),height:300,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:50,r:50,t:50,b:50}};Plotly.newPlot(o,[t],i,{responsive:!0})}else if("2D"===l&&"contour"===n){let e;e=Array.isArray(r[0])?r.map((e=>e[0])):r;let t=Math.min(window.innerWidth,700),l=Math.max(...s),d=Math.max(...i)/l,c=Math.min(t,600),u={title:`${n} plot - ${a}`,width:c,height:c*d,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"},m={x:s,y:i,z:e,type:"contour",line:{smoothing:.85},contours:{coloring:"heatmap",showlabels:!1},colorbar:{title:"Solution"},name:"Solution Field"};Plotly.newPlot(o,[m],u,{responsive:!0})}}function oe(e,t,n,o){const{nodesXCoordinates:s,nodesYCoordinates:i}=t.nodesCoordinates,r=e.meshConfig.meshDimension,a=V(e.meshConfig),l=new w({meshDimension:e.meshConfig.meshDimension,elementOrder:e.meshConfig.elementOrder});if("1D"===r&&"line"===n);else if("2D"===r&&"contour"===n){const r=[],d=[];let c=[];const u=100,m=100,h=(Math.max(...s)-Math.min(...s))/(u-1),f=(Math.max(...i)-Math.min(...i))/(m-1);r[0]=Math.min(...s),d[0]=Math.min(...i);for(let e=1;e[])),r=Array(o).fill(0);for(let e=0;ee[0])):a;let u=0;for(let e=0;et!=l>t&&e<(a-i)*(t-r)/(l-r)+i&&(o=!o)}return o}class ae{constructor(){this.worker=null,this.feaWorker=null,this.isReady=!1,this._initWorker()}async _initWorker(){try{this.worker=new Worker(new URL("./wrapperScript.js",import.meta.url),{type:"module"}),this.worker.onerror=e=>{console.error("FEAScriptWorker: Worker error:",e)};const e=p(this.worker);this.feaWorker=await new e,this.isReady=!0}catch(e){throw console.error("Failed to initialize worker",e),e}}async _ensureReady(){return this.isReady?Promise.resolve():new Promise(((e,t)=>{let n=0;const o=()=>{n++,this.isReady?e():n>=50?t(new Error("Timeout waiting for worker to be ready")):setTimeout(o,1e3)};o()}))}async setSolverConfig(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver config to: ${e}`),this.feaWorker.setSolverConfig(e)}async setMeshConfig(e){return await this._ensureReady(),s("FEAScriptWorker: Setting mesh config"),this.feaWorker.setMeshConfig(e)}async addBoundaryCondition(e,t){return await this._ensureReady(),s(`FEAScriptWorker: Adding boundary condition for boundary: ${e}`),this.feaWorker.addBoundaryCondition(e,t)}async setSolverMethod(e){return await this._ensureReady(),s(`FEAScriptWorker: Setting solver method to: ${e}`),this.feaWorker.setSolverMethod(e)}async solve(){await this._ensureReady(),s("FEAScriptWorker: Requesting solution from worker...");const e=performance.now(),t=await this.feaWorker.solve();return s(`FEAScriptWorker: Solution completed in ${((performance.now()-e)/1e3).toFixed(2)}s`),t}async getModelInfo(){return await this._ensureReady(),this.feaWorker.getModelInfo()}async ping(){return await this._ensureReady(),this.feaWorker.ping()}terminate(){this.worker&&(this.worker.terminate(),this.worker=null,this.feaWorker=null,this.isReady=!1)}}const le="0.2.0 (RC)";export{ee as FEAScriptModel,ae as FEAScriptWorker,te as importGmshQuadTri,n as logSystem,oe as plotInterpolatedSolution,ne as plotSolution,le as printVersion}; //# sourceMappingURL=feascript.esm.js.map diff --git a/dist/feascript.esm.js.map b/dist/feascript.esm.js.map index 1a7ece7..cca34b0 100644 --- a/dist/feascript.esm.js.map +++ b/dist/feascript.esm.js.map @@ -1 +1 @@ -{"version":3,"file":"feascript.esm.js","sources":["../src/methods/euclideanNormScript.js","../src/utilities/loggingScript.js","../src/vendor/comlink.mjs","../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/models/thermalBoundaryConditionsScript.js","../src/models/heatConductionScript.js","../src/models/genericBoundaryConditionsScript.js","../src/models/frontPropagationScript.js","../src/methods/frontalSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/FEAScript.js","../src/models/generalFormPDEScript.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.js","../src/workers/workerScript.js","../src/index.js"],"sourcesContent":["/**\n * ════════════════════════════════════════════════════════════\n * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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;\");\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;\");\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;\");\n}\n\n/**\n * Function to log warning messages\n * @param {string} message - Message to log\n */\nexport function warnLog(message) {\n console.log(\"%c[WARN] \" + message, \"color: #FF9800; font-weight: bold;\");\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 * @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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { jacobiSolver } from \"./jacobiSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\nimport * as Comlink from \"../vendor/comlink.mjs\";\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] - Optional parameters for the solver, such as `maxIterations` and `tolerance`\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\n // Extract options\n const { maxIterations = 10000, tolerance = 1e-4 } = 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// Helper to lazily create a default WebGPU compute engine (Comlink + worker)\nasync function createDefaultComputeEngine() {\n const worker = new Worker(new URL(\"../workers/webgpuWorkerScript.js\", import.meta.url), {\n type: \"module\",\n });\n const computeEngine = Comlink.wrap(worker);\n await computeEngine.initialize();\n return { computeEngine, worker };\n}\n\n/**\n * Function to solve asynchronously a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (e.g., \"jacobi-gpu\")\n * @param {array} jacobianMatrix - The coefficient matrix\n * @param {array} residualVector - The right-hand side vector\n * @param {object} [options] - Optional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {Promise} A promise that resolves to 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 async function solveLinearSystemAsync(solverMethod, jacobianMatrix, residualVector, options = {}) {\n \n // Extract options\n const { maxIterations = 10000, tolerance = 1e-4 } = options;\n\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n // Normalize inputs\n const A = Array.isArray(jacobianMatrix) ? jacobianMatrix : jacobianMatrix?.toArray?.() ?? jacobianMatrix;\n const b = Array.isArray(residualVector) ? residualVector : residualVector?.toArray?.() ?? residualVector;\n\n let created = null;\n let computeEngine = null;\n\n let solutionVector = [];\n let converged = true;\n let iterations;\n\n if (solverMethod === \"jacobi-gpu\") {\n // Spin up a worker-backed compute engine\n created = await createDefaultComputeEngine();\n computeEngine = created.computeEngine;\n\n const x0 = new Array(b.length).fill(0);\n let result;\n\n result = await computeEngine.webgpuJacobiSolver(A, b, x0, { maxIterations, tolerance });\n solutionVector = result.solutionVector;\n converged = result.converged;\n iterations = result.iterations;\n\n // Log convergence information\n if (converged) {\n debugLog(`Jacobi method converged in ${iterations} iterations`);\n } else {\n errorLog(`Jacobi method did not converge after ${iterations} iterations`);\n }\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(`System solved successfully (${solverMethod})`);\n\n if (created) {\n await computeEngine?.destroy?.().catch(() => { });\n created.worker.terminate();\n }\n\n return { solutionVector, converged, iterations };\n}\n","/**\n * ════════════════════════════════════════════════════════════\n * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method (CPU synchronous version)\n * @param {array} A - The system matrix\n * @param {array} b - The right-hand side vector\n * @param {array} x0 - Initial guess for solution vector\n * @param {object} [options] - Optional parameters for the solver, such as `maxIterations` and `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(A, b, x0, options = {}) {\n // Extract options\n const { maxIterations, tolerance } = options;\n\n const n = A.length;\n let x = [...x0];\n let xNew = new Array(n);\n\n // Jacobi update: xNew[i] = (b[i] - sum(A[i][j] * x[j] for j != i)) / A[i][i]\n for (let iter = 0; iter < maxIterations; iter++) {\n for (let i = 0; i < n; i++) {\n let sum = 0;\n for (let j = 0; j < n; j++) {\n if (i !== j) {\n sum += A[i][j] * x[j];\n }\n }\n xNew[i] = (b[i] - sum) / A[i][i];\n }\n\n // Check convergence based on maximum difference in solution vector\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 // Copy new solution for the next iteration\n x = [...xNew];\n\n if (maxDiff < tolerance) {\n return { solutionVector: x, iterations: iter + 1, converged: true };\n }\n }\n\n return { solutionVector: x, iterations: maxIterations, converged: false };\n}\n","/**\n * ════════════════════════════════════════════════════════════\n * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { initializeFEA } from \"../mesh/meshUtilsScript.js\";\nimport { assembleHeatConductionFront } from \"../models/heatConductionScript.js\";\nimport { ThermalBoundaryConditions } from \"../models/thermalBoundaryConditionsScript.js\";\nimport { assembleFrontPropagationFront } from \"../models/frontPropagationScript.js\";\nimport { GenericBoundaryConditions } from \"../models/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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 \"../models/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 * @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 = {}) {\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 // Extract context\n const { maxIterations = 100, tolerance = 1e-4 } = context;\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { solveLinearSystemAsync } from \"./methods/linearSystemSolverScript.js\";\nimport { prepareMesh } from \"./mesh/meshUtilsScript.js\";\nimport { assembleFrontPropagationMat } from \"./models/frontPropagationScript.js\";\nimport { assembleGeneralFormPDEMat, assembleGeneralFormPDEFront } from \"./models/generalFormPDEScript.js\";\nimport { assembleHeatConductionMat, assembleHeatConductionFront } from \"./models/heatConductionScript.js\";\nimport { runFrontalSolver } from \"./methods/frontalSolverScript.js\";\nimport { basicLog, debugLog, warnLog, 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 containifng 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 warnLog(\n \"FEAScript is provided “as is” without any warranty. The authors are not responsible for any damages or losses that may result from using the software. See the license for more details: https://github.com/FEAScript/FEAScript-core/blob/main/LICENSE\"\n );\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?.coefficientFunctions) {\n this.coefficientFunctions = options.coefficientFunctions;\n debugLog(\"Coefficient functions set\");\n }\n // Only update if a value is provided, otherwise keep the default\n if (options?.maxIterations !== undefined) {\n this.maxIterations = options.maxIterations;\n }\n if (options?.tolerance !== undefined) {\n this.tolerance = options.tolerance;\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 /**\n * Function to solve the finite element problem synchronously\n * @param {object} [options] - Additional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {object} An object containing the solution vector and the coordinates of the mesh nodes\n */\n solve(options = {}) {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n errorLog(\"Solver config, mesh config, and boundary conditions must be set before solving.\");\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 basicLog(`Using solver: ${this.solverConfig}`);\n if (this.solverConfig === \"heatConductionScript\") {\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 maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n });\n solutionVector = linearSystemResult.solutionVector;\n }\n } else if (this.solverConfig === \"frontPropagationScript\") {\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 // TODO: Consider using different maxIterations/tolerance for Newton-Raphson and linear solver\n maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\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);\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 // 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 maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n });\n solutionVector = linearSystemResult.solutionVector;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n\n /**\n * Function to solve the finite element problem asynchronously\n * @param {object} computeEngine - The compute engine to use for the asynchronous solver (e.g., a worker or a WebGPU context)\n * @param {object} [options] - Additional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {Promise} A promise that resolves to an object containing the solution vector and the coordinates of the mesh nodes\n */\n async solveAsync(computeEngine, options = {}) {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n errorLog(\"Solver config, mesh config, and boundary conditions must be set before solving.\");\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n\n basicLog(\"Preparing mesh...\");\n const meshData = prepareMesh(this.meshConfig);\n basicLog(\"Mesh preparation completed\");\n const nodesCoordinates = {\n nodesXCoordinates: meshData.nodesXCoordinates,\n nodesYCoordinates: meshData.nodesYCoordinates,\n };\n\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n\n basicLog(`Using solver: ${this.solverConfig}`);\n if (this.solverConfig === \"heatConductionScript\") {\n ({ jacobianMatrix, residualVector } = assembleHeatConductionMat(meshData, this.boundaryConditions));\n\n if (this.solverMethod === \"jacobi-gpu\") {\n const { solutionVector: x } = await solveLinearSystemAsync(\"jacobi-gpu\", jacobianMatrix, residualVector, {\n computeEngine,\n maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n });\n solutionVector = x;\n } else {\n // Other async solver\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n\n}\n","/**\n * ════════════════════════════════════════════════════════════\n * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId\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: nodesXCoordinates,\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 plotWidth = Math.min(maxWindowWidth, 600);\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: 50, r: 50, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Check if solutionVector is a nested array\n let zData;\n if (Array.isArray(solutionVector[0])) {\n zData = solutionVector.map((val) => val[0]);\n } else {\n zData = solutionVector;\n }\n\n // Sizing parameters\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;\n\n // 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 // Create the plot\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zData,\n type: \"contour\",\n line: {\n smoothing: 0.85,\n },\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 Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n}\n","/**\n * ════════════════════════════════════════════════════════════\n * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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.4\";"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","logSystem","level","console","log","basicLog","debugLog","message","errorLog","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","value","serialized","Error","isError","name","stack","Object","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","map","fromWireValue","returnValue","parent","slice","reduce","prop","rawValue","apply","proxy","transfers","transferCache","set","transfer","undefined","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","constructor","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","Array","prototype","concat","handler","serializedValue","msg","fill","floor","random","Number","MAX_SAFE_INTEGER","join","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","jacobianMatrixSparse","math","sparse","luFactorization","slu","solutionMatrix","lusolve","squeeze","valueOf","jacobiSolverResult","A","b","x0","n","x","xNew","iter","sum","j","maxDiff","max","abs","jacobiSolver","timeEnd","async","solveLinearSystemAsync","isArray","toArray","created","computeEngine","worker","Worker","URL","url","Comlink.wrap","initialize","createDefaultComputeEngine","result","webgpuJacobiSolver","destroy","terminate","BasisFunctions","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","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","boundaryElements","fixedBoundaryElements","boundaryNodePairs","forEach","dimension","tag","nodesPair","node1","node2","foundElement","elemNodes","includes","side","node1Index","indexOf","node2Index","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","prepareMesh","meshConfig","mesh","nodesCoordinatesAndNumbering","totalElements","totalNodes","initializeFEA","meshData","colIndex","basisFunctions","gaussPointsAndWeights","localToGlobalMap","numNodes","performIsoparametricMapping1D","params","xCoordinates","ksiDerivX","localNodeIndex","detJacobian","basisFunctionDerivX","performIsoparametricMapping2D","yCoordinates","etaDerivX","ksiDerivY","etaDerivY","basisFunctionDerivY","ThermalBoundaryConditions","boundaryConditions","imposeConstantTempBoundaryConditions","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","localResidualVector","boundaryElement","find","_","assembleHeatConductionMat","FEAData","gaussPointIndex1","mappingResult","localNodeIndex1","localToGlobalMap1","localToGlobalMap2","gaussPointIndex2","thermalBoundaryConditions","assembleHeatConductionFront","ngl","globalIndex","GenericBoundaryConditions","imposeDirichletBoundaryConditions","imposeConstantValueBoundaryConditionsFront","assembleFrontPropagationMat","eikonalActivationFlag","eikonalViscousTerm","solutionDerivX","solutionDerivY","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","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","nodesCoordinates","boundaryLocalJacobianMatrix","boundaryResidualVector","isOnRobinTypeBoundary","some","localNodeI","localNodeJ","iterationIndex","accumulatedValue","newtonRaphson","assembleMat","context","errorNorm","initialSolution","FEAScriptModel","solverConfig","coefficientFunctions","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","eikonalExteralIterations","newtonRaphsonResult","B","C","D","xCoord","a","d","globalNodeIndex1","assembleGeneralFormPDEMat","solveAsync","importGmshQuadTri","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","plotSolution","plotType","plotDivId","yData","from","lineData","mode","color","width","maxWindowWidth","min","window","innerWidth","layout","title","height","xaxis","yaxis","margin","l","t","Plotly","newPlot","responsive","zData","aspectRatio","plotWidth","hovermode","contourData","z","smoothing","contours","coloring","showlabels","colorbar","FEAScriptWorker","feaWorker","isReady","_initWorker","onerror","event","workerWrapper","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","toFixed","getModelInfo","ping","printVersion"],"mappings":"AAaO,SAASA,EAAcC,GAC5B,IAAIC,EAAO,EACX,IAAK,IAAIC,EAAI,EAAGA,EAAIF,EAAOG,OAAQD,IACjCD,GAAQD,EAAOE,GAAKF,EAAOE,GAG7B,OADAD,EAAOG,KAAKC,KAAKJ,GACVA,CACT,CCXA,IAAIK,EAAkB,QAMf,SAASC,EAAUC,GACV,UAAVA,GAA+B,UAAVA,GACvBC,QAAQC,IACN,+BAAiCF,EAAQ,yBACzC,sCAEFF,EAAkB,UAElBA,EAAkBE,EAClBG,EAAS,qBAAqBH,KAElC,CAMO,SAASI,EAASC,GACC,UAApBP,GACFG,QAAQC,IAAI,aAAeG,EAAS,qCAExC,CAMO,SAASF,EAASE,GACvBJ,QAAQC,IAAI,YAAcG,EAAS,qCACrC,CAMO,SAASC,EAASD,GACvBJ,QAAQC,IAAI,aAAeG,EAAS,qCACtC;;;;;;AC/CA,MAAME,EAAcC,OAAO,iBACrBC,EAAiBD,OAAO,oBACxBE,EAAeF,OAAO,wBACtBG,EAAYH,OAAO,qBACnBI,EAAcJ,OAAO,kBACrBK,EAAYC,GAAwB,iBAARA,GAA4B,OAARA,GAAgC,mBAARA,EAgDxEC,EAAmB,IAAIC,IAAI,CAC7B,CAAC,QA7CwB,CACzBC,UAAYH,GAAQD,EAASC,IAAQA,EAAIP,GACzC,SAAAW,CAAUC,GACN,MAAMC,MAAEA,EAAKC,MAAEA,GAAU,IAAIC,eAE7B,OADAC,EAAOJ,EAAKC,GACL,CAACC,EAAO,CAACA,GACnB,EACDG,YAAYC,IACRA,EAAKC,QACEC,EAAKF,MAqChB,CAAC,QA/BwB,CACzBR,UAAYW,GAAUf,EAASe,IAAUhB,KAAegB,EACxD,SAAAV,EAAUU,MAAEA,IACR,IAAIC,EAcJ,OAZIA,EADAD,aAAiBE,MACJ,CACTC,SAAS,EACTH,MAAO,CACHvB,QAASuB,EAAMvB,QACf2B,KAAMJ,EAAMI,KACZC,MAAOL,EAAMK,QAKR,CAAEF,SAAS,EAAOH,SAE5B,CAACC,EAAY,GACvB,EACD,WAAAL,CAAYK,GACR,GAAIA,EAAWE,QACX,MAAMG,OAAOC,OAAO,IAAIL,MAAMD,EAAWD,MAAMvB,SAAUwB,EAAWD,OAExE,MAAMC,EAAWD,KACpB,MAoBL,SAASL,EAAOJ,EAAKiB,EAAKC,WAAYC,EAAiB,CAAC,MACpDF,EAAGG,iBAAiB,WAAW,SAASC,EAASC,GAC7C,IAAKA,IAAOA,EAAGC,KACX,OAEJ,IAhBR,SAAyBJ,EAAgBK,GACrC,IAAK,MAAMC,KAAiBN,EAAgB,CACxC,GAAIK,IAAWC,GAAmC,MAAlBA,EAC5B,OAAO,EAEX,GAAIA,aAAyBC,QAAUD,EAAcE,KAAKH,GACtD,OAAO,CAEd,CACD,OAAO,CACX,CAMaI,CAAgBT,EAAgBG,EAAGE,QAEpC,YADA1C,QAAQ+C,KAAK,mBAAmBP,EAAGE,6BAGvC,MAAMM,GAAEA,EAAEC,KAAEA,EAAIC,KAAEA,GAASjB,OAAOC,OAAO,CAAEgB,KAAM,IAAMV,EAAGC,MACpDU,GAAgBX,EAAGC,KAAKU,cAAgB,IAAIC,IAAIC,GACtD,IAAIC,EACJ,IACI,MAAMC,EAASL,EAAKM,MAAM,GAAI,GAAGC,QAAO,CAACvC,EAAKwC,IAASxC,EAAIwC,IAAOxC,GAC5DyC,EAAWT,EAAKO,QAAO,CAACvC,EAAKwC,IAASxC,EAAIwC,IAAOxC,GACvD,OAAQ+B,GACJ,IAAK,MAEGK,EAAcK,EAElB,MACJ,IAAK,MAEGJ,EAAOL,EAAKM,OAAO,GAAG,IAAMH,EAAcb,EAAGC,KAAKd,OAClD2B,GAAc,EAElB,MACJ,IAAK,QAEGA,EAAcK,EAASC,MAAML,EAAQJ,GAEzC,MACJ,IAAK,YAGGG,EA+LxB,SAAepC,GACX,OAAOe,OAAOC,OAAOhB,EAAK,CAAEZ,CAACA,IAAc,GAC/C,CAjMsCuD,CADA,IAAIF,KAAYR,IAGlC,MACJ,IAAK,WACD,CACI,MAAMhC,MAAEA,EAAKC,MAAEA,GAAU,IAAIC,eAC7BC,EAAOJ,EAAKE,GACZkC,EAoLxB,SAAkBpC,EAAK4C,GAEnB,OADAC,EAAcC,IAAI9C,EAAK4C,GAChB5C,CACX,CAvLsC+C,CAAS9C,EAAO,CAACA,GAClC,CACD,MACJ,IAAK,UAEGmC,OAAcY,EAElB,MACJ,QACI,OAEX,CACD,MAAOvC,GACH2B,EAAc,CAAE3B,QAAOhB,CAACA,GAAc,EACzC,CACDwD,QAAQC,QAAQd,GACXe,OAAO1C,IACD,CAAEA,QAAOhB,CAACA,GAAc,MAE9B2D,MAAMhB,IACP,MAAOiB,EAAWC,GAAiBC,EAAYnB,GAC/CnB,EAAGuC,YAAYzC,OAAOC,OAAOD,OAAOC,OAAO,GAAIqC,GAAY,CAAEvB,OAAOwB,GACvD,YAATvB,IAEAd,EAAGwC,oBAAoB,UAAWpC,GAClCqC,EAAczC,GACVzB,KAAaQ,GAAiC,mBAAnBA,EAAIR,IAC/BQ,EAAIR,KAEX,IAEA2D,OAAOQ,IAER,MAAON,EAAWC,GAAiBC,EAAY,CAC3C9C,MAAO,IAAImD,UAAU,+BACrBnE,CAACA,GAAc,IAEnBwB,EAAGuC,YAAYzC,OAAOC,OAAOD,OAAOC,OAAO,GAAIqC,GAAY,CAAEvB,OAAOwB,EAAc,GAE9F,IACQrC,EAAGV,OACHU,EAAGV,OAEX,CAIA,SAASmD,EAAcG,IAHvB,SAAuBA,GACnB,MAAqC,gBAA9BA,EAASC,YAAYjD,IAChC,EAEQkD,CAAcF,IACdA,EAASG,OACjB,CACA,SAASxD,EAAKS,EAAIgD,GACd,MAAMC,EAAmB,IAAIrE,IAiB7B,OAhBAoB,EAAGG,iBAAiB,WAAW,SAAuBE,GAClD,MAAMC,KAAEA,GAASD,EACjB,IAAKC,IAASA,EAAKO,GACf,OAEJ,MAAMqC,EAAWD,EAAiBE,IAAI7C,EAAKO,IAC3C,GAAKqC,EAGL,IACIA,EAAS5C,EACZ,CACO,QACJ2C,EAAiBG,OAAO9C,EAAKO,GAChC,CACT,IACWwC,EAAYrD,EAAIiD,EAAkB,GAAID,EACjD,CACA,SAASM,EAAqBC,GAC1B,GAAIA,EACA,MAAM,IAAI7D,MAAM,6CAExB,CACA,SAAS8D,EAAgBxD,GACrB,OAAOyD,EAAuBzD,EAAI,IAAIpB,IAAO,CACzCkC,KAAM,YACPqB,MAAK,KACJM,EAAczC,EAAG,GAEzB,CACA,MAAM0D,EAAe,IAAIC,QACnBC,EAAkB,yBAA0B3D,YAC9C,IAAI4D,sBAAsB7D,IACtB,MAAM8D,GAAYJ,EAAaP,IAAInD,IAAO,GAAK,EAC/C0D,EAAa7B,IAAI7B,EAAI8D,GACJ,IAAbA,GACAN,EAAgBxD,EACnB,IAcT,SAASqD,EAAYrD,EAAIiD,EAAkBlC,EAAO,GAAIiC,EAAS,cAC3D,IAAIe,GAAkB,EACtB,MAAMrC,EAAQ,IAAIsC,MAAMhB,EAAQ,CAC5B,GAAAG,CAAIc,EAAS1C,GAET,GADA+B,EAAqBS,GACjBxC,IAASjD,EACT,MAAO,MAXvB,SAAyBoD,GACjBkC,GACAA,EAAgBM,WAAWxC,EAEnC,CAQoByC,CAAgBzC,GAChB8B,EAAgBxD,GAChBiD,EAAiBmB,QACjBL,GAAkB,CAAI,EAG9B,GAAa,SAATxC,EAAiB,CACjB,GAAoB,IAAhBR,EAAKxD,OACL,MAAO,CAAE4E,KAAM,IAAMT,GAEzB,MAAM2C,EAAIZ,EAAuBzD,EAAIiD,EAAkB,CACnDnC,KAAM,MACNC,KAAMA,EAAKE,KAAKqD,GAAMA,EAAEC,eACzBpC,KAAKjB,GACR,OAAOmD,EAAElC,KAAKqC,KAAKH,EACtB,CACD,OAAOhB,EAAYrD,EAAIiD,EAAkB,IAAIlC,EAAMQ,GACtD,EACD,GAAAM,CAAIoC,EAAS1C,EAAMC,GACf8B,EAAqBS,GAGrB,MAAOvE,EAAO6C,GAAiBC,EAAYd,GAC3C,OAAOiC,EAAuBzD,EAAIiD,EAAkB,CAChDnC,KAAM,MACNC,KAAM,IAAIA,EAAMQ,GAAMN,KAAKqD,GAAMA,EAAEC,aACnC/E,SACD6C,GAAeF,KAAKjB,EAC1B,EACD,KAAAO,CAAMwC,EAASQ,EAAUC,GACrBpB,EAAqBS,GACrB,MAAMY,EAAO5D,EAAKA,EAAKxD,OAAS,GAChC,GAAIoH,IAAStG,EACT,OAAOoF,EAAuBzD,EAAIiD,EAAkB,CAChDnC,KAAM,aACPqB,KAAKjB,GAGZ,GAAa,SAATyD,EACA,OAAOtB,EAAYrD,EAAIiD,EAAkBlC,EAAKM,MAAM,GAAI,IAE5D,MAAOL,EAAcqB,GAAiBuC,EAAiBF,GACvD,OAAOjB,EAAuBzD,EAAIiD,EAAkB,CAChDnC,KAAM,QACNC,KAAMA,EAAKE,KAAKqD,GAAMA,EAAEC,aACxBvD,gBACDqB,GAAeF,KAAKjB,EAC1B,EACD,SAAA2D,CAAUZ,EAASS,GACfpB,EAAqBS,GACrB,MAAO/C,EAAcqB,GAAiBuC,EAAiBF,GACvD,OAAOjB,EAAuBzD,EAAIiD,EAAkB,CAChDnC,KAAM,YACNC,KAAMA,EAAKE,KAAKqD,GAAMA,EAAEC,aACxBvD,gBACDqB,GAAeF,KAAKjB,EAC1B,IAGL,OA9EJ,SAAuBQ,EAAO1B,GAC1B,MAAM8D,GAAYJ,EAAaP,IAAInD,IAAO,GAAK,EAC/C0D,EAAa7B,IAAI7B,EAAI8D,GACjBF,GACAA,EAAgBkB,SAASpD,EAAO1B,EAAI0B,EAE5C,CAuEIqD,CAAcrD,EAAO1B,GACd0B,CACX,CAIA,SAASkD,EAAiB5D,GACtB,MAAMgE,EAAYhE,EAAaC,IAAIqB,GACnC,MAAO,CAAC0C,EAAU/D,KAAKgE,GAAMA,EAAE,MALnBC,EAK+BF,EAAU/D,KAAKgE,GAAMA,EAAE,KAJ3DE,MAAMC,UAAUC,OAAO5D,MAAM,GAAIyD,KAD5C,IAAgBA,CAMhB,CACA,MAAMtD,EAAgB,IAAI+B,QAe1B,SAASrB,EAAY9C,GACjB,IAAK,MAAOI,EAAM0F,KAAY3G,EAC1B,GAAI2G,EAAQzG,UAAUW,GAAQ,CAC1B,MAAO+F,EAAiBlD,GAAiBiD,EAAQxG,UAAUU,GAC3D,MAAO,CACH,CACIsB,KAAM,UACNlB,OACAJ,MAAO+F,GAEXlD,EAEP,CAEL,MAAO,CACH,CACIvB,KAAM,MACNtB,SAEJoC,EAAcuB,IAAI3D,IAAU,GAEpC,CACA,SAAS0B,EAAc1B,GACnB,OAAQA,EAAMsB,MACV,IAAK,UACD,OAAOnC,EAAiBwE,IAAI3D,EAAMI,MAAMR,YAAYI,EAAMA,OAC9D,IAAK,MACD,OAAOA,EAAMA,MAEzB,CACA,SAASiE,EAAuBzD,EAAIiD,EAAkBuC,EAAK7D,GACvD,OAAO,IAAIK,SAASC,IAChB,MAAMpB,EASH,IAAIsE,MAAM,GACZM,KAAK,GACLxE,KAAI,IAAMzD,KAAKkI,MAAMlI,KAAKmI,SAAWC,OAAOC,kBAAkBtB,SAAS,MACvEuB,KAAK,KAXN7C,EAAiBpB,IAAIhB,EAAIoB,GACrBjC,EAAGV,OACHU,EAAGV,QAEPU,EAAGuC,YAAYzC,OAAOC,OAAO,CAAEc,MAAM2E,GAAM7D,EAAU,GAE7D,CCpUO,SAASoE,EAAkBC,EAAcC,EAAgBC,EAAgBC,EAAU,CAAA,GAGxF,MAAMC,cAAEA,EAAgB,IAAKC,UAAEA,EAAY,MAASF,EAEpD,IAAIG,EAAiB,GACjBC,GAAY,EACZC,EAAa,EAMjB,GAHAzI,EAAS,wBAAwBiI,QACjCnI,QAAQ4I,KAAK,iBAEQ,YAAjBT,EAA4B,CAE9B,MAAMU,EAAuBC,KAAKC,OAAOX,GACnCY,EAAkBF,KAAKG,IAAIJ,EAAsB,EAAG,GAC1D,IAAIK,EAAiBJ,KAAKK,QAAQH,EAAiBX,GACnDI,EAAiBK,KAAKM,QAAQF,GAAgBG,SAElD,MAAS,GAAqB,WAAjBlB,EAA2B,CAEpC,MACMmB,EC5BH,SAAsBC,EAAGC,EAAGC,EAAInB,EAAU,CAAA,GAE/C,MAAMC,cAAEA,EAAaC,UAAEA,GAAcF,EAE/BoB,EAAIH,EAAE7J,OACZ,IAAIiK,EAAI,IAAIF,GACRG,EAAO,IAAItC,MAAMoC,GAGrB,IAAK,IAAIG,EAAO,EAAGA,EAAOtB,EAAesB,IAAQ,CAC/C,IAAK,IAAIpK,EAAI,EAAGA,EAAIiK,EAAGjK,IAAK,CAC1B,IAAIqK,EAAM,EACV,IAAK,IAAIC,EAAI,EAAGA,EAAIL,EAAGK,IACjBtK,IAAMsK,IACRD,GAAOP,EAAE9J,GAAGsK,GAAKJ,EAAEI,IAGvBH,EAAKnK,IAAM+J,EAAE/J,GAAKqK,GAAOP,EAAE9J,GAAGA,EAC/B,CAGD,IAAIuK,EAAU,EACd,IAAK,IAAIvK,EAAI,EAAGA,EAAIiK,EAAGjK,IACrBuK,EAAUrK,KAAKsK,IAAID,EAASrK,KAAKuK,IAAIN,EAAKnK,GAAKkK,EAAElK,KAMnD,GAFAkK,EAAI,IAAIC,GAEJI,EAAUxB,EACZ,MAAO,CAAEC,eAAgBkB,EAAGhB,WAAYkB,EAAO,EAAGnB,WAAW,EAEhE,CAED,MAAO,CAAED,eAAgBkB,EAAGhB,WAAYJ,EAAeG,WAAW,EACpE,CDP+ByB,CAAa/B,EAAgBC,EADnC,IAAIf,MAAMe,EAAe3I,QAAQkI,KAAK,GAC2B,CACpFW,gBACAC,cAIEc,EAAmBZ,UACrBvI,EAAS,8BAA8BmJ,EAAmBX,yBAE1DtI,EAAS,wCAAwCiJ,EAAmBX,yBAGtEF,EAAiBa,EAAmBb,eACpCC,EAAYY,EAAmBZ,UAC/BC,EAAaW,EAAmBX,UACpC,MACItI,EAAS,0BAA0B8H,KAMrC,OAHAnI,QAAQoK,QAAQ,iBAChBlK,EAAS,8BAEF,CAAEuI,iBAAgBC,YAAWC,aACtC,CAuBO0B,eAAeC,EAAuBnC,EAAcC,EAAgBC,EAAgBC,EAAU,CAAA,GAGnG,MAAMC,cAAEA,EAAgB,IAAKC,UAAEA,EAAY,MAASF,EAEpDpI,EAAS,wBAAwBiI,QACjCnI,QAAQ4I,KAAK,iBAGb,MAAMW,EAAIjC,MAAMiD,QAAQnC,GAAkBA,EAAiBA,GAAgBoC,aAAepC,EACpFoB,EAAIlC,MAAMiD,QAAQlC,GAAkBA,EAAiBA,GAAgBmC,aAAenC,EAE1F,IAKIM,EALA8B,EAAU,KACVC,EAAgB,KAEhBjC,EAAiB,GACjBC,GAAY,EAGhB,GAAqB,eAAjBP,EAA+B,CAEjCsC,QAzCJJ,iBACE,MAAMM,EAAS,IAAIC,OAAO,IAAIC,IAAI,+CAAgDC,KAAM,CACtF7H,KAAM,WAEFyH,EAAgBK,EAAaJ,GAEnC,aADMD,EAAcM,aACb,CAAEN,gBAAeC,SAC1B,CAkCoBM,GAChBP,EAAgBD,EAAQC,cAExB,MAAMjB,EAAK,IAAInC,MAAMkC,EAAE9J,QAAQkI,KAAK,GACpC,IAAIsD,EAEJA,QAAeR,EAAcS,mBAAmB5B,EAAGC,EAAGC,EAAI,CAAElB,gBAAeC,cAC3EC,EAAiByC,EAAOzC,eACxBC,EAAYwC,EAAOxC,UACnBC,EAAauC,EAAOvC,WAGhBD,EACFvI,EAAS,8BAA8BwI,gBAEvCtI,EAAS,wCAAwCsI,eAEvD,MACItI,EAAS,0BAA0B8H,KAWrC,OARAnI,QAAQoK,QAAQ,iBAChBlK,EAAS,+BAA+BiI,MAEpCsC,UACIC,GAAeU,YAAY/G,OAAM,UACvCoG,EAAQE,OAAOU,aAGV,CAAE5C,iBAAgBC,YAAWC,aACtC,CElIO,MAAM2C,EAMX,WAAAtG,EAAYuG,cAAEA,EAAaC,aAAEA,IAC3BC,KAAKF,cAAgBA,EACrBE,KAAKD,aAAeA,CACrB,CAWD,iBAAAE,CAAkBC,EAAKC,EAAM,MAC3B,IAAIC,EAAgB,GAChBC,EAAwB,GACxBC,EAAwB,GAE5B,GAA2B,OAAvBN,KAAKF,cACmB,WAAtBE,KAAKD,cAEPK,EAAc,GAAK,EAAIF,EACvBE,EAAc,GAAKF,EAGnBG,EAAsB,IAAM,EAC5BA,EAAsB,GAAK,GACI,cAAtBL,KAAKD,eAEdK,EAAc,GAAK,EAAI,EAAIF,EAAM,EAAIA,GAAO,EAC5CE,EAAc,GAAK,EAAIF,EAAM,EAAIA,GAAO,EACxCE,EAAc,GAAY,EAAIF,GAAO,EAAjBA,EAGpBG,EAAsB,GAAU,EAAIH,EAAR,EAC5BG,EAAsB,GAAK,EAAI,EAAIH,EACnCG,EAAsB,GAAU,EAAIH,EAAR,QAEzB,GAA2B,OAAvBF,KAAKF,cAAwB,CACtC,GAAY,OAARK,EAEF,YADAvL,EAAS,8CAIX,GAA0B,WAAtBoL,KAAKD,aAA2B,CAElC,SAASQ,EAAGC,GACV,OAAO,EAAIA,CACZ,CAYDJ,EAAc,GAAKG,EAAGL,GAAOK,EAAGJ,GAChCC,EAAc,GAAKG,EAAGL,GAAUC,EAChCC,EAAc,GAAQF,EAAOK,EAAGJ,GAChCC,EAAc,GAAQF,EAAUC,EAGhCE,EAAsB,IAbZ,EAayBE,EAAGJ,GACtCE,EAAsB,IAdZ,EAc4BF,EACtCE,EAAsB,GAZb,EAY0BE,EAAGJ,GACtCE,EAAsB,GAbb,EAa6BF,EAGtCG,EAAsB,IAnBZ,EAmBiBC,EAAGL,GAC9BI,EAAsB,GAjBb,EAiBkBC,EAAGL,GAC9BI,EAAsB,IArBZ,EAqBoBJ,EAC9BI,EAAsB,GAnBb,EAmBqBJ,CACtC,MAAa,GAA0B,cAAtBF,KAAKD,aAA8B,CAE5C,SAASQ,EAAGC,GACV,OAAO,EAAIA,GAAK,EAAI,EAAIA,EAAI,CAC7B,CACD,SAASC,EAAGD,GACV,OAAQ,EAAIA,GAAK,EAAI,EAAIA,CAC1B,CACD,SAASE,EAAGF,GACV,OAAO,EAAIA,GAAK,EAAIA,CACrB,CACD,SAASG,EAAIH,GACX,OAAO,EAAIA,EAAI,CAChB,CACD,SAASI,EAAIJ,GACX,OAAQ,EAAIA,EAAI,CACjB,CACD,SAASK,EAAIL,GACX,OAAO,EAAIA,EAAI,CAChB,CAGDJ,EAAc,GAAKG,EAAGL,GAAOK,EAAGJ,GAChCC,EAAc,GAAKG,EAAGL,GAAOO,EAAGN,GAChCC,EAAc,GAAKG,EAAGL,GAAOQ,EAAGP,GAChCC,EAAc,GAAKK,EAAGP,GAAOK,EAAGJ,GAChCC,EAAc,GAAKK,EAAGP,GAAOO,EAAGN,GAChCC,EAAc,GAAKK,EAAGP,GAAOQ,EAAGP,GAChCC,EAAc,GAAKM,EAAGR,GAAOK,EAAGJ,GAChCC,EAAc,GAAKM,EAAGR,GAAOO,EAAGN,GAChCC,EAAc,GAAKM,EAAGR,GAAOQ,EAAGP,GAGhCE,EAAsB,GAAKM,EAAIT,GAAOK,EAAGJ,GACzCE,EAAsB,GAAKM,EAAIT,GAAOO,EAAGN,GACzCE,EAAsB,GAAKM,EAAIT,GAAOQ,EAAGP,GACzCE,EAAsB,GAAKO,EAAIV,GAAOK,EAAGJ,GACzCE,EAAsB,GAAKO,EAAIV,GAAOO,EAAGN,GACzCE,EAAsB,GAAKO,EAAIV,GAAOQ,EAAGP,GACzCE,EAAsB,GAAKQ,EAAIX,GAAOK,EAAGJ,GACzCE,EAAsB,GAAKQ,EAAIX,GAAOO,EAAGN,GACzCE,EAAsB,GAAKQ,EAAIX,GAAOQ,EAAGP,GAGzCG,EAAsB,GAAKC,EAAGL,GAAOS,EAAIR,GACzCG,EAAsB,GAAKC,EAAGL,GAAOU,EAAIT,GACzCG,EAAsB,GAAKC,EAAGL,GAAOW,EAAIV,GACzCG,EAAsB,GAAKG,EAAGP,GAAOS,EAAIR,GACzCG,EAAsB,GAAKG,EAAGP,GAAOU,EAAIT,GACzCG,EAAsB,GAAKG,EAAGP,GAAOW,EAAIV,GACzCG,EAAsB,GAAKI,EAAGR,GAAOS,EAAIR,GACzCG,EAAsB,GAAKI,EAAGR,GAAOU,EAAIT,GACzCG,EAAsB,GAAKI,EAAGR,GAAOW,EAAIV,EAC1C,CACF,CAED,MAAO,CAAEC,gBAAeC,wBAAuBC,wBAChD,EC5II,MAAMQ,EAYX,WAAAvH,EAAYwH,aACVA,EAAe,KAAIC,KACnBA,EAAO,KAAIC,aACXA,EAAe,KAAIC,KACnBA,EAAO,KAAIpB,cACXA,EAAgB,KAAIC,aACpBA,EAAe,SAAQoB,WACvBA,EAAa,OAEbnB,KAAKe,aAAeA,EACpBf,KAAKiB,aAAeA,EACpBjB,KAAKgB,KAAOA,EACZhB,KAAKkB,KAAOA,EACZlB,KAAKF,cAAgBA,EACrBE,KAAKD,aAAeA,EACpBC,KAAKmB,WAAaA,EAElBnB,KAAKoB,2BAA4B,EAE7BpB,KAAKmB,aACP1M,EAAS,mEACTuL,KAAKqB,oBAER,CAKD,iBAAAA,GAKE,GAJKrB,KAAKmB,WAAWG,gBACnB1M,EAAS,sDAIiC,iBAAnCoL,KAAKmB,WAAWG,iBACtBzF,MAAMiD,QAAQkB,KAAKmB,WAAWG,gBAC/B,CAEA,MAAMC,EAAevB,KAAKmB,WAAWG,eAAeC,cAAgB,GASpE,GARyBvB,KAAKmB,WAAWG,eAAeE,iBAExD9M,EACE,yDACE+M,KAAKC,UAAU1B,KAAKmB,WAAWG,iBAI/BtB,KAAKmB,WAAWQ,aAAa,IAAM3B,KAAKmB,WAAWQ,aAAa,IAAK,CAEvE,MAAMC,EAAuB,GAE7B,IAAK,IAAIC,EAAU,EAAGA,EAAUN,EAAatN,OAAQ4N,IAAW,CAC9D,MAAMC,EAAYP,EAAaM,GACzBE,EAAiB,IAAIlG,MAAMiG,EAAU7N,QAGlB,IAArB6N,EAAU7N,QAOZ8N,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,IACA,IAArBA,EAAU7N,SASnB8N,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,GAC9BC,EAAe,GAAKD,EAAU,IAGhCF,EAAqBI,KAAKD,EAC3B,CAED/B,KAAKmB,WAAWG,eAAiBM,CAClC,MAAU5B,KAAKmB,WAAWQ,aAAa,IACtC/M,EAAS,4FASX,GANAF,EACE,gEACE+M,KAAKC,UAAU1B,KAAKmB,WAAWG,iBAI/BtB,KAAKmB,WAAWc,iBAAmBjC,KAAKmB,WAAWe,iBAAkB,CAEvE,GACErG,MAAMiD,QAAQkB,KAAKmB,WAAWe,mBAC9BlC,KAAKmB,WAAWe,iBAAiBjO,OAAS,QACFwE,IAAxCuH,KAAKmB,WAAWe,iBAAiB,GACjC,CAEA,MAAMC,EAAwB,GAC9B,IAAK,IAAInO,EAAI,EAAGA,EAAIgM,KAAKmB,WAAWe,iBAAiBjO,OAAQD,IACvDgM,KAAKmB,WAAWe,iBAAiBlO,IACnCmO,EAAsBH,KAAKhC,KAAKmB,WAAWe,iBAAiBlO,IAGhEgM,KAAKmB,WAAWe,iBAAmBC,CACpC,CAGD,GAAInC,KAAKmB,WAAWiB,oBAAsBpC,KAAKmB,WAAWC,4BAExDpB,KAAKmB,WAAWe,iBAAmB,GAGnClC,KAAKmB,WAAWc,gBAAgBI,SAASpK,IAEvC,GAAuB,IAAnBA,EAAKqK,UAAiB,CAExB,MAAMF,EAAoBpC,KAAKmB,WAAWiB,kBAAkBnK,EAAKsK,MAAQ,GAErEH,EAAkBnO,OAAS,IAExB+L,KAAKmB,WAAWe,iBAAiBjK,EAAKsK,OACzCvC,KAAKmB,WAAWe,iBAAiBjK,EAAKsK,KAAO,IAI/CH,EAAkBC,SAASG,IACzB,MAAMC,EAAQD,EAAU,GAClBE,EAAQF,EAAU,GAExB9N,EACE,mCAAmC+N,MAAUC,mBAAuBzK,EAAKsK,QACvEtK,EAAK3B,MAAQ,cAKjB,IAAIqM,GAAe,EAGnB,IAAK,IAAId,EAAU,EAAGA,EAAU7B,KAAKmB,WAAWG,eAAerN,OAAQ4N,IAAW,CAChF,MAAMe,EAAY5C,KAAKmB,WAAWG,eAAeO,GAGjD,GAAyB,IAArBe,EAAU3O,QAEZ,GAAI2O,EAAUC,SAASJ,IAAUG,EAAUC,SAASH,GAAQ,CAE1D,IAAII,EAEJ,MAAMC,EAAaH,EAAUI,QAAQP,GAC/BQ,EAAaL,EAAUI,QAAQN,GAErChO,EACE,mBAAmBmN,gDAAsDe,EAAUpG,KACjF,UAGJ9H,EACE,UAAU+N,iBAAqBM,WAAoBL,iBAAqBO,oBASxD,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBH,EAAO,EACPpO,EAAS,uCAAuCoO,iBAAoBjB,MAEpD,IAAfkB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBH,EAAO,EACPpO,EAAS,qCAAqCoO,iBAAoBjB,MAElD,IAAfkB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBH,EAAO,EACPpO,EAAS,oCAAoCoO,iBAAoBjB,OAEjD,IAAfkB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,KAErBH,EAAO,EACPpO,EAAS,sCAAsCoO,iBAAoBjB,MAIrE7B,KAAKmB,WAAWe,iBAAiBjK,EAAKsK,KAAKP,KAAK,CAACH,EAASiB,IAC1DpO,EACE,8BAA8BmN,MAAYiB,sBAAyB7K,EAAKsK,OAE1EI,GAAe,EACf,KACD,OACI,GAAyB,IAArBC,EAAU3O,QAGf2O,EAAUC,SAASJ,IAAUG,EAAUC,SAASH,GAAQ,CAE1D,IAAII,EAEJ,MAAMC,EAAaH,EAAUI,QAAQP,GAC/BQ,EAAaL,EAAUI,QAAQN,GAErChO,EACE,mBAAmBmN,gDAAsDe,EAAUpG,KACjF,UAGJ9H,EACE,UAAU+N,iBAAqBM,WAAoBL,iBAAqBO,oBAYxD,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBH,EAAO,EACPpO,EAAS,uCAAuCoO,iBAAoBjB,MAEpD,IAAfkB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBH,EAAO,EACPpO,EAAS,qCAAqCoO,iBAAoBjB,MAElD,IAAfkB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GAErBH,EAAO,EACPpO,EAAS,oCAAoCoO,iBAAoBjB,OAEjD,IAAfkB,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,GACL,IAAfF,GAAmC,IAAfE,KAErBH,EAAO,EACPpO,EAAS,sCAAsCoO,iBAAoBjB,MAIrE7B,KAAKmB,WAAWe,iBAAiBjK,EAAKsK,KAAKP,KAAK,CAACH,EAASiB,IAC1DpO,EACE,8BAA8BmN,MAAYiB,sBAAyB7K,EAAKsK,OAE1EI,GAAe,EACf,KACD,CAEJ,CAEIA,GACH/N,EACE,oDAAoD6N,SAAaC,iCAEpE,IAGN,KAIH1C,KAAKoB,2BAA4B,EAI/BpB,KAAKmB,WAAWe,iBAAiBjO,OAAS,QACFwE,IAAxCuH,KAAKmB,WAAWe,iBAAiB,IACjC,CACA,MAAMC,EAAwB,GAC9B,IAAK,IAAInO,EAAI,EAAGA,EAAIgM,KAAKmB,WAAWe,iBAAiBjO,OAAQD,IACvDgM,KAAKmB,WAAWe,iBAAiBlO,IACnCmO,EAAsBH,KAAKhC,KAAKmB,WAAWe,iBAAiBlO,IAGhEgM,KAAKmB,WAAWe,iBAAmBC,CACpC,CAEJ,CACF,CAED,OAAOnC,KAAKmB,UACb,EAGI,MAAM+B,UAAepC,EAS1B,WAAAvH,EAAYwH,aAAEA,EAAe,KAAIC,KAAEA,EAAO,KAAIjB,aAAEA,EAAe,SAAQoB,WAAEA,EAAa,OACpFgC,MAAM,CACJpC,eACAC,OACAC,aAAc,EACdC,KAAM,EACNpB,cAAe,KACfC,eACAoB,eAGwB,OAAtBnB,KAAKe,cAAuC,OAAdf,KAAKgB,MACrCpM,EAAS,wFAEZ,CAED,YAAAwO,GACE,IAAIC,EAAoB,GAExB,IAAIC,EAAaC,EAEjB,GAA0B,WAAtBvD,KAAKD,aAA2B,CAClCuD,EAActD,KAAKe,aAAe,EAClCwC,GAAUvD,KAAKgB,KALF,GAKmBhB,KAAKe,aAErCsC,EAAkB,GAPL,EAQb,IAAK,IAAIG,EAAY,EAAGA,EAAYF,EAAaE,IAC/CH,EAAkBG,GAAaH,EAAkBG,EAAY,GAAKD,CAE1E,MAAW,GAA0B,cAAtBvD,KAAKD,aAA8B,CAC5CuD,EAAc,EAAItD,KAAKe,aAAe,EACtCwC,GAAUvD,KAAKgB,KAbF,GAamBhB,KAAKe,aAErCsC,EAAkB,GAfL,EAgBb,IAAK,IAAIG,EAAY,EAAGA,EAAYF,EAAaE,IAC/CH,EAAkBG,GAAaH,EAAkBG,EAAY,GAAKD,EAAS,CAE9E,CAED,MAAMjC,EAAiBtB,KAAKyD,yBAAyBzD,KAAKe,aAAcuC,EAAatD,KAAKD,cAEpFmC,EAAmBlC,KAAK0D,uBAK9B,OAHAhP,EAAS,iCAAmC+M,KAAKC,UAAU2B,IAGpD,CACLA,oBACAC,cACAhC,iBACAY,mBAEH,CAUD,wBAAAuB,CAAyB1C,EAAcuC,EAAavD,GAKlD,IAAI4D,EAAM,GAEV,GAAqB,WAAjB5D,EAOF,IAAK,IAAI6D,EAAe,EAAGA,EAAe7C,EAAc6C,IAAgB,CACtED,EAAIC,GAAgB,GACpB,IAAK,IAAIJ,EAAY,EAAGA,GAAa,EAAGA,IACtCG,EAAIC,GAAcJ,EAAY,GAAKI,EAAeJ,CAErD,MACI,GAAqB,cAAjBzD,EAA8B,CAOvC,IAAI8D,EAAgB,EACpB,IAAK,IAAID,EAAe,EAAGA,EAAe7C,EAAc6C,IAAgB,CACtED,EAAIC,GAAgB,GACpB,IAAK,IAAIJ,EAAY,EAAGA,GAAa,EAAGA,IACtCG,EAAIC,GAAcJ,EAAY,GAAKI,EAAeJ,EAAYK,EAEhEA,GAAiB,CAClB,CACF,CAED,OAAOF,CACR,CAYD,oBAAAD,GACE,MAAMxB,EAAmB,GAEzB,IAAK,IAAI4B,EAAY,EAAGA,EADP,EAC6BA,IAC5C5B,EAAiBF,KAAK,IAWxB,OAPAE,EAAiB,GAAGF,KAAK,CAAC,EAAG,IAG7BE,EAAiB,GAAGF,KAAK,CAAChC,KAAKe,aAAe,EAAG,IAEjDrM,EAAS,yCAA2C+M,KAAKC,UAAUQ,IACnElC,KAAKoB,2BAA4B,EAC1Bc,CACR,EAGI,MAAM6B,UAAejD,EAW1B,WAAAvH,EAAYwH,aACVA,EAAe,KAAIC,KACnBA,EAAO,KAAIC,aACXA,EAAe,KAAIC,KACnBA,EAAO,KAAInB,aACXA,EAAe,SAAQoB,WACvBA,EAAa,OAEbgC,MAAM,CACJpC,eACAC,OACAC,eACAC,OACApB,cAAe,KACfC,eACAoB,eAKCA,GACsB,OAAtBnB,KAAKe,cAAuC,OAAdf,KAAKgB,MAAuC,OAAtBhB,KAAKiB,cAAuC,OAAdjB,KAAKkB,MAExFtM,EACE,6GAGL,CAED,YAAAwO,GACE,IAAIC,EAAoB,GACpBW,EAAoB,GAGxB,IAAIV,EAAaW,EAAaV,EAAQW,EAEtC,GAA0B,WAAtBlE,KAAKD,aAA2B,CAClCuD,EAActD,KAAKe,aAAe,EAClCkD,EAAcjE,KAAKiB,aAAe,EAClCsC,GAAUvD,KAAKgB,KAPF,GAOmBhB,KAAKe,aACrCmD,GAAUlE,KAAKkB,KAPF,GAOmBlB,KAAKiB,aAErCoC,EAAkB,GAVL,EAWbW,EAAkB,GAVL,EAWb,IAAK,IAAIG,EAAa,EAAGA,EAAaF,EAAaE,IACjDd,EAAkBc,GAAcd,EAAkB,GAClDW,EAAkBG,GAAcH,EAAkB,GAAKG,EAAaD,EAEtE,IAAK,IAAIE,EAAa,EAAGA,EAAad,EAAac,IAAc,CAC/D,MAAMC,EAAQD,EAAaH,EAC3BZ,EAAkBgB,GAAShB,EAAkB,GAAKe,EAAab,EAC/DS,EAAkBK,GAASL,EAAkB,GAC7C,IAAK,IAAIG,EAAa,EAAGA,EAAaF,EAAaE,IACjDd,EAAkBgB,EAAQF,GAAcd,EAAkBgB,GAC1DL,EAAkBK,EAAQF,GAAcH,EAAkBK,GAASF,EAAaD,CAEnF,CACP,MAAW,GAA0B,cAAtBlE,KAAKD,aAA8B,CAC5CuD,EAAc,EAAItD,KAAKe,aAAe,EACtCkD,EAAc,EAAIjE,KAAKiB,aAAe,EACtCsC,GAAUvD,KAAKgB,KA5BF,GA4BmBhB,KAAKe,aACrCmD,GAAUlE,KAAKkB,KA5BF,GA4BmBlB,KAAKiB,aAErCoC,EAAkB,GA/BL,EAgCbW,EAAkB,GA/BL,EAgCb,IAAK,IAAIG,EAAa,EAAGA,EAAaF,EAAaE,IACjDd,EAAkBc,GAAcd,EAAkB,GAClDW,EAAkBG,GAAcH,EAAkB,GAAMG,EAAaD,EAAU,EAEjF,IAAK,IAAIE,EAAa,EAAGA,EAAad,EAAac,IAAc,CAC/D,MAAMC,EAAQD,EAAaH,EAC3BZ,EAAkBgB,GAAShB,EAAkB,GAAMe,EAAab,EAAU,EAC1ES,EAAkBK,GAASL,EAAkB,GAC7C,IAAK,IAAIG,EAAa,EAAGA,EAAaF,EAAaE,IACjDd,EAAkBgB,EAAQF,GAAcd,EAAkBgB,GAC1DL,EAAkBK,EAAQF,GAAcH,EAAkBK,GAAUF,EAAaD,EAAU,CAE9F,CACF,CAGD,MAAM5C,EAAiBtB,KAAKsE,yBAC1BtE,KAAKe,aACLf,KAAKiB,aACLgD,EACAjE,KAAKD,cAIDmC,EAAmBlC,KAAK0D,uBAM9B,OAJAhP,EAAS,iCAAmC+M,KAAKC,UAAU2B,IAC3D3O,EAAS,iCAAmC+M,KAAKC,UAAUsC,IAGpD,CACLX,oBACAW,oBACAV,cACAW,cACA3C,iBACAY,mBAEH,CAYD,wBAAAoC,CAAyBvD,EAAcE,EAAcgD,EAAalE,GAChE,IAAI6D,EAAe,EACfD,EAAM,GAEV,GAAqB,WAAjB5D,EAA2B,CAS7B,IAAIwE,EAAa,EACbV,EAAgB,EACpB,IAAK,IAAID,EAAe,EAAGA,EAAe7C,EAAeE,EAAc2C,IACrEW,GAAc,EACdZ,EAAIC,GAAgB,GACpBD,EAAIC,GAAc,GAAKA,EAAeC,EAAgB,EACtDF,EAAIC,GAAc,GAAKA,EAAeC,EACtCF,EAAIC,GAAc,GAAKA,EAAeC,EAAgB5C,EACtD0C,EAAIC,GAAc,GAAKA,EAAeC,EAAgB5C,EAAe,EACjEsD,IAAetD,IACjB4C,GAAiB,EACjBU,EAAa,EAGvB,MAAW,GAAqB,cAAjBxE,EAWT,IAAK,IAAIyE,EAAgB,EAAGA,GAAiBzD,EAAcyD,IACzD,IAAK,IAAIC,EAAgB,EAAGA,GAAiBxD,EAAcwD,IAAiB,CAC1Ed,EAAIC,GAAgB,GACpB,IAAK,IAAIc,EAAa,EAAGA,GAAc,EAAGA,IAAc,CACtD,IAAIC,EAAa,EAAID,EAAa,EAClCf,EAAIC,GAAce,EAAa,GAC7BV,GAAe,EAAIO,EAAgBE,EAAa,GAAK,EAAID,EAAgB,EAC3Ed,EAAIC,GAAce,GAAchB,EAAIC,GAAce,EAAa,GAAK,EACpEhB,EAAIC,GAAce,EAAa,GAAKhB,EAAIC,GAAce,EAAa,GAAK,CACzE,CACDf,GAA8B,CAC/B,CAIL,OAAOD,CACR,CAcD,oBAAAD,GACE,MAAMxB,EAAmB,GAGzB,IAAK,IAAI4B,EAAY,EAAGA,EAFP,EAE6BA,IAC5C5B,EAAiBF,KAAK,IAMxB,IAAK,IAAIwC,EAAgB,EAAGA,EAAgBxE,KAAKe,aAAcyD,IAC7D,IAAK,IAAIC,EAAgB,EAAGA,EAAgBzE,KAAKiB,aAAcwD,IAAiB,CAC9E,MAAMb,EAAeY,EAAgBxE,KAAKiB,aAAewD,EAGnC,IAAlBA,GACFvC,EAAiB,GAAGF,KAAK,CAAC4B,EAAc,IAIpB,IAAlBY,GACFtC,EAAiB,GAAGF,KAAK,CAAC4B,EAAc,IAItCa,IAAkBzE,KAAKiB,aAAe,GACxCiB,EAAiB,GAAGF,KAAK,CAAC4B,EAAc,IAItCY,IAAkBxE,KAAKe,aAAe,GACxCmB,EAAiB,GAAGF,KAAK,CAAC4B,EAAc,GAE3C,CAKH,OAFAlP,EAAS,yCAA2C+M,KAAKC,UAAUQ,IACnElC,KAAKoB,2BAA4B,EAC1Bc,CACR,EC3sBI,MAAM0C,EAMX,WAAArL,EAAYuG,cAAEA,EAAaC,aAAEA,IAC3BC,KAAKF,cAAgBA,EACrBE,KAAKD,aAAeA,CACrB,CAQD,wBAAA8E,GACE,IAAIC,EAAc,GACdC,EAAe,GAgBnB,MAd0B,WAAtB/E,KAAKD,cAEP+E,EAAY,GAAK,GACjBC,EAAa,GAAK,GACa,cAAtB/E,KAAKD,eAEd+E,EAAY,IAAM,EAAI5Q,KAAKC,KAAK,KAAU,EAC1C2Q,EAAY,GAAK,GACjBA,EAAY,IAAM,EAAI5Q,KAAKC,KAAK,KAAU,EAC1C4Q,EAAa,GAAK,EAAI,GACtBA,EAAa,GAAK,EAAI,GACtBA,EAAa,GAAK,EAAI,IAGjB,CAAED,cAAaC,eACvB,EC7BI,SAASC,EAAYC,GAC1B,MAAMnF,cAAEA,EAAaiB,aAAEA,EAAYE,aAAEA,EAAYD,KAAEA,EAAIE,KAAEA,EAAInB,aAAEA,EAAYoB,WAAEA,GAAe8D,EAG5F,IAAIC,EACkB,OAAlBpF,EACFoF,EAAO,IAAIhC,EAAO,CAAEnC,eAAcC,OAAMjB,eAAcoB,eAC3B,OAAlBrB,EACToF,EAAO,IAAInB,EAAO,CAAEhD,eAAcC,OAAMC,eAAcC,OAAMnB,eAAcoB,eAE1EvM,EAAS,+CAIX,MAAMuQ,EAA+BD,EAAK9D,0BAA4B8D,EAAK/D,WAAa+D,EAAK9B,eAG7F,IAAIC,EAAoB8B,EAA6B9B,kBACjDW,EAAoBmB,EAA6BnB,kBACjDV,EAAc6B,EAA6B7B,YAC3CW,EAAckB,EAA6BlB,YAC3CN,EAAMwB,EAA6B7D,eACnCY,EAAmBiD,EAA6BjD,iBAMpD,IAAIkD,EAAeC,EAanB,OAhBqBlE,SAMnBiE,EAAgBzB,EAAI1P,OACpBoR,EAAahC,EAAkBpP,OAC/BS,EAAS,0BAA0B0Q,kBAA8BC,aAGjED,EAAgBrE,GAAkC,OAAlBjB,EAAyBmB,EAAe,GACxEoE,EAAa/B,GAAiC,OAAlBxD,EAAyBmE,EAAc,GACnEvP,EAAS,2CAA2C0Q,kBAA8BC,YAG7E,CACLhC,oBACAW,oBACAV,cACAW,cACAN,MACAzB,mBACAkD,gBACAC,aACAvF,gBACAC,eAEJ,CAOO,SAASuF,EAAcC,GAC5B,MAAMF,WAAEA,EAAU1B,IAAEA,EAAG7D,cAAEA,EAAaC,aAAEA,GAAiBwF,EAGzD,IAAI3I,EAAiB,GACjBD,EAAiB,GAIrB,IAAK,IAAI6G,EAAY,EAAGA,EAAY6B,EAAY7B,IAAa,CAC3D5G,EAAe4G,GAAa,EAC5B7G,EAAeqF,KAAK,IACpB,IAAK,IAAIwD,EAAW,EAAGA,EAAWH,EAAYG,IAC5C7I,EAAe6G,GAAWgC,GAAY,CAEzC,CAGD,MAAMC,EAAiB,IAAI5F,EAAe,CACxCC,gBACAC,iBAUF,IAAI2F,EANyB,IAAId,EAAqB,CACpD9E,gBACAC,iBAI+C8E,2BAOjD,MAAO,CACLjI,iBACAD,iBACAgJ,iBAlCqB,GAmCrBF,iBACAX,YAXgBY,EAAsBZ,YAYtCC,aAXiBW,EAAsBX,aAYvCa,SATejC,EAAI,GAAG1P,OAW1B,CAOO,SAAS4R,EAA8BC,GAC5C,MAAM1F,cAAEA,EAAaC,sBAAEA,EAAqBgD,kBAAEA,EAAiBsC,iBAAEA,EAAgBC,SAAEA,GAAaE,EAEhG,IAAIC,EAAe,EACfC,EAAY,EAGhB,IAAK,IAAIC,EAAiB,EAAGA,EAAiBL,EAAUK,IACtDF,GAAgB1C,EAAkBsC,EAAiBM,IAAmB7F,EAAc6F,GACpFD,GAAa3C,EAAkBsC,EAAiBM,IAAmB5F,EAAsB4F,GAE3F,IAAIC,EAAcF,EAGdG,EAAsB,GAC1B,IAAK,IAAIF,EAAiB,EAAGA,EAAiBL,EAAUK,IACtDE,EAAoBF,GAAkB5F,EAAsB4F,GAAkBC,EAGhF,MAAO,CACLH,eACAG,cACAC,sBAEJ,CAOO,SAASC,EAA8BN,GAC5C,MAAM1F,cACJA,EAAaC,sBACbA,EAAqBC,sBACrBA,EAAqB+C,kBACrBA,EAAiBW,kBACjBA,EAAiB2B,iBACjBA,EAAgBC,SAChBA,GACEE,EAEJ,IAAIC,EAAe,EACfM,EAAe,EACfL,EAAY,EACZM,EAAY,EACZC,EAAY,EACZC,EAAY,EAGhB,IAAK,IAAIP,EAAiB,EAAGA,EAAiBL,EAAUK,IACtDF,GAAgB1C,EAAkBsC,EAAiBM,IAAmB7F,EAAc6F,GACpFI,GAAgBrC,EAAkB2B,EAAiBM,IAAmB7F,EAAc6F,GACpFD,GAAa3C,EAAkBsC,EAAiBM,IAAmB5F,EAAsB4F,GACzFK,GAAajD,EAAkBsC,EAAiBM,IAAmB3F,EAAsB2F,GACzFM,GAAavC,EAAkB2B,EAAiBM,IAAmB5F,EAAsB4F,GACzFO,GAAaxC,EAAkB2B,EAAiBM,IAAmB3F,EAAsB2F,GAE3F,IAAIC,EAAcF,EAAYQ,EAAYF,EAAYC,EAGlDJ,EAAsB,GACtBM,EAAsB,GAC1B,IAAK,IAAIR,EAAiB,EAAGA,EAAiBL,EAAUK,IAEtDE,EAAoBF,IACjBO,EAAYnG,EAAsB4F,GACjCM,EAAYjG,EAAsB2F,IACpCC,EAEFO,EAAoBR,IACjBD,EAAY1F,EAAsB2F,GACjCK,EAAYjG,EAAsB4F,IACpCC,EAGJ,MAAO,CACLH,eACAM,eACAH,cACAC,sBACAM,sBAEJ,CCxMO,MAAMC,EASX,WAAAnN,CAAYoN,EAAoBzE,EAAkByB,EAAK7D,EAAeC,GACpEC,KAAK2G,mBAAqBA,EAC1B3G,KAAKkC,iBAAmBA,EACxBlC,KAAK2D,IAAMA,EACX3D,KAAKF,cAAgBA,EACrBE,KAAKD,aAAeA,CACrB,CAeD,oCAAA6G,CAAqChK,EAAgBD,GACxB,OAAvBqD,KAAKF,cACPtJ,OAAOqQ,KAAK7G,KAAK2G,oBAAoBtE,SAASyE,IAC5C,GAAgD,iBAA5C9G,KAAK2G,mBAAmBG,GAAa,GAAuB,CAC9D,MAAMC,EAAY/G,KAAK2G,mBAAmBG,GAAa,GACvDpS,EACE,YAAYoS,uCAAiDC,6BAE/D/G,KAAKkC,iBAAiB4E,GAAazE,SAAQ,EAAEuB,EAAcd,MACzD,GAA0B,WAAtB9C,KAAKD,aAA2B,EACZ,CACpB,EAAG,CAAC,GACJ,EAAG,CAAC,KAEQ+C,GAAMT,SAASmB,IAC3B,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAC5D9O,EACE,4CAA4CsS,EAAkB,cAC5DpD,EAAe,iBACDJ,EAAY,MAG9B5G,EAAeoK,GAAmBD,EAElC,IAAK,IAAIvB,EAAW,EAAGA,EAAW5I,EAAe3I,OAAQuR,IACvD7I,EAAeqK,GAAiBxB,GAAY,EAG9C7I,EAAeqK,GAAiBA,GAAmB,CAAC,GAEpE,MAAmB,GAA0B,cAAtBhH,KAAKD,aAA8B,EACtB,CACpB,EAAG,CAAC,GACJ,EAAG,CAAC,KAEQ+C,GAAMT,SAASmB,IAC3B,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAC5D9O,EACE,4CAA4CsS,EAAkB,cAC5DpD,EAAe,iBACDJ,EAAY,MAG9B5G,EAAeoK,GAAmBD,EAElC,IAAK,IAAIvB,EAAW,EAAGA,EAAW5I,EAAe3I,OAAQuR,IACvD7I,EAAeqK,GAAiBxB,GAAY,EAG9C7I,EAAeqK,GAAiBA,GAAmB,CAAC,GAEvD,IAEJ,KAE6B,OAAvBhH,KAAKF,eACdtJ,OAAOqQ,KAAK7G,KAAK2G,oBAAoBtE,SAASyE,IAC5C,GAAgD,iBAA5C9G,KAAK2G,mBAAmBG,GAAa,GAAuB,CAC9D,MAAMC,EAAY/G,KAAK2G,mBAAmBG,GAAa,GACvDpS,EACE,YAAYoS,uCAAiDC,6BAE/D/G,KAAKkC,iBAAiB4E,GAAazE,SAAQ,EAAEuB,EAAcd,MACzD,GAA0B,WAAtB9C,KAAKD,aAA2B,EACZ,CACpB,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,KAEK+C,GAAMT,SAASmB,IAC3B,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAC5D9O,EACE,4CAA4CsS,EAAkB,cAC5DpD,EAAe,iBACDJ,EAAY,MAG9B5G,EAAeoK,GAAmBD,EAElC,IAAK,IAAIvB,EAAW,EAAGA,EAAW5I,EAAe3I,OAAQuR,IACvD7I,EAAeqK,GAAiBxB,GAAY,EAG9C7I,EAAeqK,GAAiBA,GAAmB,CAAC,GAEpE,MAAmB,GAA0B,cAAtBhH,KAAKD,aAA8B,EACtB,CACpB,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,KAEE+C,GAAMT,SAASmB,IAC3B,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAC5D9O,EACE,4CAA4CsS,EAAkB,cAC5DpD,EAAe,iBACDJ,EAAY,MAG9B5G,EAAeoK,GAAmBD,EAElC,IAAK,IAAIvB,EAAW,EAAGA,EAAW5I,EAAe3I,OAAQuR,IACvD7I,EAAeqK,GAAiBxB,GAAY,EAG9C7I,EAAeqK,GAAiBA,GAAmB,CAAC,GAEvD,IAEJ,IAGN,CAOD,yCAAAC,CAA0CC,EAAoBC,GACjC,OAAvBnH,KAAKF,cACPtJ,OAAOqQ,KAAK7G,KAAK2G,oBAAoBtE,SAASyE,IAC5C,GAAgD,iBAA5C9G,KAAK2G,mBAAmBG,GAAa,GAAuB,CAC9D,MAAMC,EAAY/G,KAAK2G,mBAAmBG,GAAa,GACvDpS,EACE,YAAYoS,uCAAiDC,6BAG/D/G,KAAKkC,iBAAiB4E,GAAazE,SAAQ,EAAEuB,EAAcd,MACzD,GAA0B,WAAtB9C,KAAKD,aAA2B,EACZ,CACpB,EAAG,CAAC,GACJ,EAAG,CAAC,KAGQ+C,GAAMT,SAASmB,IAC3B,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAC5D9O,EACE,4CAA4CsS,EAAkB,cAC5DpD,EAAe,iBACDJ,EAAY,MAI9B0D,EAAmBF,GAAmB,EACtCG,EAAeH,GAAmBD,CAAS,GAE3D,MAAmB,GAA0B,cAAtB/G,KAAKD,aAA8B,EACtB,CACpB,EAAG,CAAC,GACJ,EAAG,CAAC,KAGQ+C,GAAMT,SAASmB,IAC3B,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAC5D9O,EACE,4CAA4CsS,EAAkB,cAC5DpD,EAAe,iBACDJ,EAAY,MAI9B0D,EAAmBF,GAAmB,EACtCG,EAAeH,GAAmBD,CAAS,GAE9C,IAEJ,KAE6B,OAAvB/G,KAAKF,eACdtJ,OAAOqQ,KAAK7G,KAAK2G,oBAAoBtE,SAASyE,IAC5C,GAAgD,iBAA5C9G,KAAK2G,mBAAmBG,GAAa,GAAuB,CAC9D,MAAMC,EAAY/G,KAAK2G,mBAAmBG,GAAa,GACvDpS,EACE,YAAYoS,uCAAiDC,6BAG/D/G,KAAKkC,iBAAiB4E,GAAazE,SAAQ,EAAEuB,EAAcd,MACzD,GAA0B,WAAtB9C,KAAKD,aAA2B,EACZ,CACpB,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,KAGK+C,GAAMT,SAASmB,IAC3B,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAC5D9O,EACE,4CAA4CsS,EAAkB,cAC5DpD,EAAe,iBACDJ,EAAY,MAI9B0D,EAAmBF,GAAmB,EACtCG,EAAeH,GAAmBD,CAAS,GAE3D,MAAmB,GAA0B,cAAtB/G,KAAKD,aAA8B,EACtB,CACpB,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,KAGE+C,GAAMT,SAASmB,IAC3B,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAC5D9O,EACE,4CAA4CsS,EAAkB,cAC5DpD,EAAe,iBACDJ,EAAY,MAI9B0D,EAAmBF,GAAmB,EACtCG,EAAeH,GAAmBD,CAAS,GAE9C,IAEJ,IAGN,CAYD,kCAAAK,CACExK,EACAD,EACAmI,EACAC,EACA1B,EACAW,EACAyB,GAGA,IAAI4B,EAA2B,GAC3BC,EAAoB,GACxB9Q,OAAOqQ,KAAK7G,KAAK2G,oBAAoBtE,SAASkF,IAC5C,MAAMC,EAAoBxH,KAAK2G,mBAAmBY,GACrB,eAAzBC,EAAkB,KACpBH,EAAyBE,GAAOC,EAAkB,GAClDF,EAAkBC,GAAOC,EAAkB,GAC5C,IAGwB,OAAvBxH,KAAKF,cACPtJ,OAAOqQ,KAAK7G,KAAK2G,oBAAoBtE,SAASyE,IAC5C,GAAgD,eAA5C9G,KAAK2G,mBAAmBG,GAAa,GAAqB,CAC5D,MAAMW,EAAkBJ,EAAyBP,GAC3CY,EAAUJ,EAAkBR,GAClCpS,EACE,YAAYoS,2DAAqEW,0CAAwDC,OAE3I1H,KAAKkC,iBAAiB4E,GAAazE,SAAQ,EAAEuB,EAAcd,MACzD,IAAIU,EACsB,WAAtBxD,KAAKD,aAGLyD,EAFW,IAATV,EAEU,EAGA,EAEiB,cAAtB9C,KAAKD,eAGZyD,EAFW,IAATV,EAEU,EAGA,GAIhB,MAAMkE,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAC5D9O,EACE,qDAAqDsS,EAAkB,cACrEpD,EAAe,iBACDJ,EAAY,MAE9B5G,EAAeoK,KAAqBS,EAAkBC,EACtD/K,EAAeqK,GAAiBA,IAAoBS,CAAe,GAEtE,KAE6B,OAAvBzH,KAAKF,eACdtJ,OAAOqQ,KAAK7G,KAAK2G,oBAAoBtE,SAASyE,IAC5C,GAAgD,eAA5C9G,KAAK2G,mBAAmBG,GAAa,GAAqB,CAC5D,MAAMW,EAAkBJ,EAAyBP,GAC3CY,EAAUJ,EAAkBR,GAClCpS,EACE,YAAYoS,2DAAqEW,0CAAwDC,OAE3I1H,KAAKkC,iBAAiB4E,GAAazE,SAAQ,EAAEuB,EAAcd,MACzD,GAA0B,WAAtB9C,KAAKD,aAA2B,CAClC,IAAI4H,EAAaC,EAAaC,EAAgBC,EAAeC,EAChD,IAATjF,GAEF6E,EAAc7C,EAAY,GAC1B8C,EAAc,EACdC,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATjF,GAET6E,EAAc,EACdC,EAAc9C,EAAY,GAC1B+C,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATjF,GAET6E,EAAc7C,EAAY,GAC1B8C,EAAc,EACdC,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATjF,IAET6E,EAAc,EACdC,EAAc9C,EAAY,GAC1B+C,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GAGlB,IAAIC,EAA+BvC,EAAexF,kBAAkB0H,EAAaC,GAC7ExH,EAAgB4H,EAA6B5H,cAC7CC,EAAwB2H,EAA6B3H,sBACrDC,EAAwB0H,EAA6B1H,sBAErD0F,EAAY,EACZO,EAAY,EACZD,EAAY,EACZE,EAAY,EAChB,MAAMZ,EAAW5F,KAAK2D,IAAIC,GAAc3P,OACxC,IAAK,IAAIuP,EAAY,EAAGA,EAAYoC,EAAUpC,IAAa,CACzD,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAG/C,IAATV,GAAuB,IAATA,GAChBkD,GAAa3C,EAAkB2D,GAAmB3G,EAAsBmD,GACxE+C,GAAavC,EAAkBgD,GAAmB3G,EAAsBmD,IAGxD,IAATV,GAAuB,IAATA,IACrBwD,GAAajD,EAAkB2D,GAAmB1G,EAAsBkD,GACxEgD,GAAaxC,EAAkBgD,GAAmB1G,EAAsBkD,GAE3E,CAGD,IAAIyE,EAEFA,EADW,IAATnF,GAAuB,IAATA,EACM5O,KAAKC,KAAK6R,GAAa,EAAIO,GAAa,GAExCrS,KAAKC,KAAKmS,GAAa,EAAIE,GAAa,GAGhE,IACE,IAAIP,EAAiB4B,EACrB5B,EAAiB6B,EACjB7B,GAAkB8B,EAClB,CACA,IAAIf,EAAkBhH,KAAK2D,IAAIC,GAAcqC,GAAkB,EAC/DvR,EACE,qDAAqDsS,EAAkB,cACrEpD,EAAe,iBACDqC,EAAiB,MAInCrJ,EAAeoK,KACZjC,EAAa,GACdkD,EACA7H,EAAc6F,GACdwB,EACAC,EAEF,IACE,IAAIQ,EAAkBL,EACtBK,EAAkBJ,EAClBI,GAAmBH,EACnB,CACA,IAAII,EAAmBnI,KAAK2D,IAAIC,GAAcsE,GAAmB,EACjEvL,EAAeqK,GAAiBmB,KAC7BpD,EAAa,GACdkD,EACA7H,EAAc6F,GACd7F,EAAc8H,GACdT,CACH,CACF,CACf,MAAmB,GAA0B,cAAtBzH,KAAKD,aACd,IAAK,IAAIqI,EAAkB,EAAGA,EAAkB,EAAGA,IAAmB,CACpE,IAAIT,EAAaC,EAAaC,EAAgBC,EAAeC,EAChD,IAATjF,GAEF6E,EAAc7C,EAAYsD,GAC1BR,EAAc,EACdC,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATjF,GAET6E,EAAc,EACdC,EAAc9C,EAAYsD,GAC1BP,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATjF,GAET6E,EAAc7C,EAAYsD,GAC1BR,EAAc,EACdC,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATjF,IAET6E,EAAc,EACdC,EAAc9C,EAAYsD,GAC1BP,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GAElB,IAAIC,EAA+BvC,EAAexF,kBAAkB0H,EAAaC,GAC7ExH,EAAgB4H,EAA6B5H,cAC7CC,EAAwB2H,EAA6B3H,sBACrDC,EAAwB0H,EAA6B1H,sBAErD0F,EAAY,EACZO,EAAY,EACZD,EAAY,EACZE,EAAY,EAChB,MAAMZ,EAAW5F,KAAK2D,IAAIC,GAAc3P,OACxC,IAAK,IAAIuP,EAAY,EAAGA,EAAYoC,EAAUpC,IAAa,CACzD,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAG/C,IAATV,GAAuB,IAATA,GAChBkD,GAAa3C,EAAkB2D,GAAmB3G,EAAsBmD,GACxE+C,GAAavC,EAAkBgD,GAAmB3G,EAAsBmD,IAGxD,IAATV,GAAuB,IAATA,IACrBwD,GAAajD,EAAkB2D,GAAmB1G,EAAsBkD,GACxEgD,GAAaxC,EAAkBgD,GAAmB1G,EAAsBkD,GAE3E,CAGD,IAAIyE,EAEFA,EADW,IAATnF,GAAuB,IAATA,EACM5O,KAAKC,KAAK6R,GAAa,EAAIO,GAAa,GAExCrS,KAAKC,KAAKmS,GAAa,EAAIE,GAAa,GAGhE,IACE,IAAIP,EAAiB4B,EACrB5B,EAAiB6B,EACjB7B,GAAkB8B,EAClB,CACA,IAAIf,EAAkBhH,KAAK2D,IAAIC,GAAcqC,GAAkB,EAC/DvR,EACE,qDAAqDsS,EAAkB,cACrEpD,EAAe,iBACDqC,EAAiB,MAInCrJ,EAAeoK,KACZjC,EAAaqD,GACdH,EACA7H,EAAc6F,GACdwB,EACAC,EAEF,IACE,IAAIQ,EAAkBL,EACtBK,EAAkBJ,EAClBI,GAAmBH,EACnB,CACA,IAAII,EAAmBnI,KAAK2D,IAAIC,GAAcsE,GAAmB,EACjEvL,EAAeqK,GAAiBmB,KAC7BpD,EAAaqD,GACdH,EACA7H,EAAc6F,GACd7F,EAAc8H,GACdT,CACH,CACF,CACF,CACF,GAEJ,IAGN,CAcD,uCAAAY,CACEzE,EACAP,EACAW,EACAc,EACAC,EACAU,GAGA,IAAI4B,EAA2B,GAC3BC,EAAoB,GACxB9Q,OAAOqQ,KAAK7G,KAAK2G,oBAAoBtE,SAASkF,IAC5C,MAAMC,EAAoBxH,KAAK2G,mBAAmBY,GACrB,eAAzBC,EAAkB,KACpBH,EAAyBE,GAAOC,EAAkB,GAClDF,EAAkBC,GAAOC,EAAkB,GAC5C,IAIH,MAAM5B,EAAW5F,KAAK2D,IAAIC,GAAc3P,OAClCqU,EAAsBzM,MAAM+J,GAC/BzJ,OACAxE,KAAI,IAAMkE,MAAM+J,GAAUzJ,KAAK,KAC5BoM,EAAsB1M,MAAM+J,GAAUzJ,KAAK,GAGjD,IAAK,MAAM2K,KAAe9G,KAAKkC,iBAC7B,GAAkD,eAA9ClC,KAAK2G,mBAAmBG,KAAe,GAAqB,CAC9D,MAAMW,EAAkBJ,EAAyBP,GAC3CY,EAAUJ,EAAkBR,GAClCpS,EACE,YAAYoS,2DAAqEW,0CAAwDC,OAI3I,MAAMc,EAAkBxI,KAAKkC,iBAAiB4E,GAAa2B,MACzD,EAAE5G,EAAS6G,KAAO7G,IAAY+B,IAGhC,GAAI4E,EAAiB,CACnB,MAAM1F,EAAO0F,EAAgB,GAE7B,GAA2B,OAAvBxI,KAAKF,cAAwB,CAE/B,IAAI0D,EACsB,WAAtBxD,KAAKD,aACPyD,EAAqB,IAATV,EAAa,EAAI,EACE,cAAtB9C,KAAKD,eACdyD,EAAqB,IAATV,EAAa,EAAI,GAI/BpO,EACE,qDAAqD8O,EAAY,cAC/DI,EAAe,iBACDJ,EAAY,MAE9B+E,EAAoB/E,KAAeiE,EAAkBC,EACrDY,EAAoB9E,GAAWA,IAAciE,CACzD,MAAiB,GAA2B,OAAvBzH,KAAKF,cAEd,GAA0B,WAAtBE,KAAKD,aAA2B,CAClC,IAAI4H,EAAaC,EAAaC,EAAgBC,EAAeC,EAEhD,IAATjF,GAEF6E,EAAc7C,EAAY,GAC1B8C,EAAc,EACdC,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATjF,GAET6E,EAAc,EACdC,EAAc9C,EAAY,GAC1B+C,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATjF,GAET6E,EAAc7C,EAAY,GAC1B8C,EAAc,EACdC,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATjF,IAET6E,EAAc,EACdC,EAAc9C,EAAY,GAC1B+C,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GAIlB,MAAMC,EAA+BvC,EAAexF,kBAAkB0H,EAAaC,GAC7ExH,EAAgB4H,EAA6B5H,cAC7CC,EAAwB2H,EAA6B3H,sBACrDC,EAAwB0H,EAA6B1H,sBAG3D,IAiBI2H,EAjBAjC,EAAY,EACdO,EAAY,EACZD,EAAY,EACZE,EAAY,EACd,IAAK,IAAIhD,EAAY,EAAGA,EAAYoC,EAAUpC,IAAa,CACzD,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAE/C,IAATV,GAAuB,IAATA,GAChBkD,GAAa3C,EAAkB2D,GAAmB3G,EAAsBmD,GACxE+C,GAAavC,EAAkBgD,GAAmB3G,EAAsBmD,IACtD,IAATV,GAAuB,IAATA,IACvBwD,GAAajD,EAAkB2D,GAAmB1G,EAAsBkD,GACxEgD,GAAaxC,EAAkBgD,GAAmB1G,EAAsBkD,GAE3E,CAKCyE,EADW,IAATnF,GAAuB,IAATA,EACM5O,KAAKC,KAAK6R,GAAa,EAAIO,GAAa,GAExCrS,KAAKC,KAAKmS,GAAa,EAAIE,GAAa,GAIhE,IACE,IAAIP,EAAiB4B,EACrB5B,EAAiB6B,EACjB7B,GAAkB8B,EAClB,CACAQ,EAAoBtC,KACjBlB,EAAa,GACdkD,EACA7H,EAAc6F,GACdwB,EACAC,EAEF,IACE,IAAIQ,EAAkBL,EACtBK,EAAkBJ,EAClBI,GAAmBH,EAEnBO,EAAoBrC,GAAgBiC,KACjCnD,EAAa,GACdkD,EACA7H,EAAc6F,GACd7F,EAAc8H,GACdT,CAEL,CACf,MAAmB,GAA0B,cAAtBzH,KAAKD,aAEd,IAAK,IAAIqI,EAAkB,EAAGA,EAAkB,EAAGA,IAAmB,CACpE,IAAIT,EAAaC,EAAaC,EAAgBC,EAAeC,EAEhD,IAATjF,GAEF6E,EAAc7C,EAAYsD,GAC1BR,EAAc,EACdC,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATjF,GAET6E,EAAc,EACdC,EAAc9C,EAAYsD,GAC1BP,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATjF,GAET6E,EAAc7C,EAAYsD,GAC1BR,EAAc,EACdC,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GACE,IAATjF,IAET6E,EAAc,EACdC,EAAc9C,EAAYsD,GAC1BP,EAAiB,EACjBC,EAAgB,EAChBC,EAAgB,GAElB,IAAIC,EAA+BvC,EAAexF,kBAAkB0H,EAAaC,GAC7ExH,EAAgB4H,EAA6B5H,cAC7CC,EAAwB2H,EAA6B3H,sBACrDC,EAAwB0H,EAA6B1H,sBAErD0F,EAAY,EACZO,EAAY,EACZD,EAAY,EACZE,EAAY,EAChB,MAAMZ,EAAW5F,KAAK2D,IAAIC,GAAc3P,OACxC,IAAK,IAAIuP,EAAY,EAAGA,EAAYoC,EAAUpC,IAAa,CACzD,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAG/C,IAATV,GAAuB,IAATA,GAChBkD,GAAa3C,EAAkB2D,GAAmB3G,EAAsBmD,GACxE+C,GAAavC,EAAkBgD,GAAmB3G,EAAsBmD,IAGxD,IAATV,GAAuB,IAATA,IACrBwD,GAAajD,EAAkB2D,GAAmB1G,EAAsBkD,GACxEgD,GAAaxC,EAAkBgD,GAAmB1G,EAAsBkD,GAE3E,CAGD,IAAIyE,EAEFA,EADW,IAATnF,GAAuB,IAATA,EACM5O,KAAKC,KAAK6R,GAAa,EAAIO,GAAa,GAExCrS,KAAKC,KAAKmS,GAAa,EAAIE,GAAa,GAIhE,IACE,IAAIP,EAAiB4B,EACrB5B,EAAiB6B,EACjB7B,GAAkB8B,EAClB,CACAQ,EAAoBtC,KACjBlB,EAAaqD,GACdH,EACA7H,EAAc6F,GACdwB,EACAC,EAEF,IACE,IAAIQ,EAAkBL,EACtBK,EAAkBJ,EAClBI,GAAmBH,EAEnBO,EAAoBrC,GAAgBiC,KACjCnD,EAAaqD,GACdH,EACA7H,EAAc6F,GACd7F,EAAc8H,GACdT,CAEL,CACF,CAGN,CACF,CAGH,MAAO,CAAEa,sBAAqBC,sBAC/B,ECnxBI,SAASI,EAA0BpD,EAAUoB,GAClDlS,EAAS,mDAGT,MAAM4O,kBACJA,EAAiBW,kBACjBA,EAAiBL,IACjBA,EAAGzB,iBACHA,EAAgBkD,cAChBA,EAAatF,cACbA,EAAaC,aACbA,GACEwF,EAGEqD,EAAUtD,EAAcC,IACxB3I,eACJA,EAAcD,eACdA,EAAcgJ,iBACdA,EAAgBF,eAChBA,EAAcX,YACdA,EAAWC,aACXA,EAAYa,SACZA,GACEgD,EAGJ,IAAK,IAAIhF,EAAe,EAAGA,EAAewB,EAAexB,IAAgB,CAEvE,IAAK,IAAIqC,EAAiB,EAAGA,EAAiBL,EAAUK,IAEtDN,EAAiBM,GAAkBtC,EAAIC,GAAcqC,GAAkB,EAIzE,IAAK,IAAI4C,EAAmB,EAAGA,EAAmB/D,EAAY7Q,OAAQ4U,IAEpE,GAAsB,OAAlB/I,EAAwB,CAE1B,MAAMkI,EAA+BvC,EAAexF,kBAAkB6E,EAAY+D,IAG5EC,EAAgBjD,EAA8B,CAClDzF,cAAe4H,EAA6B5H,cAC5CC,sBAAuB2H,EAA6B3H,sBACpDgD,oBACAsC,mBACAC,cAIIM,YAAEA,EAAWC,oBAAEA,GAAwB2C,EAG7C,IAAK,IAAIC,EAAkB,EAAGA,EAAkBnD,EAAUmD,IAAmB,CAC3E,IAAIC,EAAoBrD,EAAiBoD,GAGzC,IAAK,IAAIb,EAAkB,EAAGA,EAAkBtC,EAAUsC,IAAmB,CAC3E,IAAIe,EAAoBtD,EAAiBuC,GACzCvL,EAAeqM,GAAmBC,KAC/BlE,EAAa8D,GACd3C,GACCC,EAAoB4C,GAAmB5C,EAAoB+B,GAC/D,CACF,CACF,MAEI,GAAsB,OAAlBpI,EACP,IAAK,IAAIoJ,EAAmB,EAAGA,EAAmBpE,EAAY7Q,OAAQiV,IAAoB,CAExF,MAAMlB,EAA+BvC,EAAexF,kBAClD6E,EAAY+D,GACZ/D,EAAYoE,IAIRJ,EAAgB1C,EAA8B,CAClDhG,cAAe4H,EAA6B5H,cAC5CC,sBAAuB2H,EAA6B3H,sBACpDC,sBAAuB0H,EAA6B1H,sBACpD+C,oBACAW,oBACA2B,mBACAC,cAIIM,YAAEA,EAAWC,oBAAEA,EAAmBM,oBAAEA,GAAwBqC,EAGlE,IAAK,IAAIC,EAAkB,EAAGA,EAAkBnD,EAAUmD,IAAmB,CAC3E,IAAIC,EAAoBrD,EAAiBoD,GAGzC,IAAK,IAAIb,EAAkB,EAAGA,EAAkBtC,EAAUsC,IAAmB,CAC3E,IAAIe,EAAoBtD,EAAiBuC,GACzCvL,EAAeqM,GAAmBC,KAC/BlE,EAAa8D,GACd9D,EAAamE,GACbhD,GACCC,EAAoB4C,GAAmB5C,EAAoB+B,GAC1DzB,EAAoBsC,GAAmBtC,EAAoByB,GAChE,CACF,CACF,CAGN,CAGD,MAAMiB,EAA4B,IAAIzC,EACpCC,EACAzE,EACAyB,EACA7D,EACAC,GAkBF,OAdAoJ,EAA0B/B,mCACxBxK,EACAD,EACAmI,EACAC,EACA1B,EACAW,EACAyB,GAIF0D,EAA0BvC,qCAAqChK,EAAgBD,GAC/ElI,EAAS,iDAEF,CACLkI,iBACAC,iBAEJ,CAcO,SAASwM,GAA4BxF,aAAEA,EAAYD,IAAEA,EAAG4B,SAAEA,EAAQE,eAAEA,EAAcmD,QAAEA,IAEzF,MAAM9D,YAAEA,EAAWC,aAAEA,EAAYa,SAAEA,GAAagD,GAC1CvF,kBAAEA,EAAiBW,kBAAEA,EAAiBlE,cAAEA,GAAkByF,EAG1D+C,EAAsBzM,MAAM+J,GAC/BzJ,OACAxE,KAAI,IAAMkE,MAAM+J,GAAUzJ,KAAK,KAC5BoM,EAAsB1M,MAAM+J,GAAUzJ,KAAK,GAG3CkN,EAAMxN,MAAM+J,GACZD,EAAmB9J,MAAM+J,GAC/B,IAAK,IAAIK,EAAiB,EAAGA,EAAiBL,EAAUK,IACtDoD,EAAIpD,GAAkB/R,KAAKuK,IAAIkF,EAAIC,GAAcqC,IACjDN,EAAiBM,GAAkB/R,KAAKuK,IAAIkF,EAAIC,GAAcqC,IAAmB,EAInF,GAAsB,OAAlBnG,EAEF,IAAK,IAAI+I,EAAmB,EAAGA,EAAmB/D,EAAY7Q,OAAQ4U,IAAoB,CAExF,MAAMzI,cAAEA,EAAaC,sBAAEA,GAA0BoF,EAAexF,kBAC9D6E,EAAY+D,KAIR3C,YAAEA,EAAWC,oBAAEA,GAAwBN,EAA8B,CACzEzF,gBACAC,wBACAgD,oBACAsC,mBACAC,aAIF,IAAK,IAAImD,EAAkB,EAAGA,EAAkBnD,EAAUmD,IACxD,IAAK,IAAIb,EAAkB,EAAGA,EAAkBtC,EAAUsC,IACxDI,EAAoBS,GAAiBb,IACnCnD,EAAa8D,GACb3C,GACCC,EAAoB4C,GAAmB5C,EAAoB+B,GAGnE,MACI,GAAsB,OAAlBpI,EAET,IAAK,IAAI+I,EAAmB,EAAGA,EAAmB/D,EAAY7Q,OAAQ4U,IACpE,IAAK,IAAIK,EAAmB,EAAGA,EAAmBpE,EAAY7Q,OAAQiV,IAAoB,CAExF,MAAM9I,cAAEA,EAAaC,sBAAEA,EAAqBC,sBAAEA,GAC5CmF,EAAexF,kBAAkB6E,EAAY+D,GAAmB/D,EAAYoE,IAGxEvD,EAAmB0D,EAAI1R,KAAK2R,GAAgBA,EAAc,KAG1DpD,YAAEA,EAAWC,oBAAEA,EAAmBM,oBAAEA,GAAwBL,EAA8B,CAC9FhG,gBACAC,wBACAC,wBACA+C,oBACAW,oBACA2B,mBACAC,aAIF,IAAK,IAAImD,EAAkB,EAAGA,EAAkBnD,EAAUmD,IACxD,IAAK,IAAIb,EAAkB,EAAGA,EAAkBtC,EAAUsC,IACxDI,EAAoBS,GAAiBb,IACnCnD,EAAa8D,GACb9D,EAAamE,GACbhD,GACCC,EAAoB4C,GAAmB5C,EAAoB+B,GAC1DzB,EAAoBsC,GAAmBtC,EAAoByB,GAGpE,CAIL,MAAO,CAAEI,sBAAqBC,sBAAqBc,MACrD,CChQO,MAAME,EASX,WAAAhQ,CAAYoN,EAAoBzE,EAAkByB,EAAK7D,EAAeC,GACpEC,KAAK2G,mBAAqBA,EAC1B3G,KAAKkC,iBAAmBA,EACxBlC,KAAK2D,IAAMA,EACX3D,KAAKF,cAAgBA,EACrBE,KAAKD,aAAeA,CACrB,CAeD,iCAAAyJ,CAAkC5M,EAAgBD,GACrB,OAAvBqD,KAAKF,cACPtJ,OAAOqQ,KAAK7G,KAAK2G,oBAAoBtE,SAASyE,IAC5C,GAAgD,kBAA5C9G,KAAK2G,mBAAmBG,GAAa,GAAwB,CAC/D,MAAM5Q,EAAQ8J,KAAK2G,mBAAmBG,GAAa,GACnDpS,EAAS,YAAYoS,iCAA2C5Q,2BAChE8J,KAAKkC,iBAAiB4E,GAAazE,SAAQ,EAAEuB,EAAcd,MACzD,GAA0B,WAAtB9C,KAAKD,aAA2B,EACZ,CACpB,EAAG,CAAC,GACJ,EAAG,CAAC,KAEQ+C,GAAMT,SAASmB,IAC3B,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAC5D9O,EACE,sCAAsCsS,EAAkB,cACtDpD,EAAe,iBACDJ,EAAY,MAG9B5G,EAAeoK,GAAmB9Q,EAElC,IAAK,IAAIsP,EAAW,EAAGA,EAAW5I,EAAe3I,OAAQuR,IACvD7I,EAAeqK,GAAiBxB,GAAY,EAG9C7I,EAAeqK,GAAiBA,GAAmB,CAAC,GAEpE,MAAmB,GAA0B,cAAtBhH,KAAKD,aAA8B,EACtB,CACpB,EAAG,CAAC,GACJ,EAAG,CAAC,KAEQ+C,GAAMT,SAASmB,IAC3B,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAC5D9O,EACE,sCAAsCsS,EAAkB,cACtDpD,EAAe,iBACDJ,EAAY,MAG9B5G,EAAeoK,GAAmB9Q,EAElC,IAAK,IAAIsP,EAAW,EAAGA,EAAW5I,EAAe3I,OAAQuR,IACvD7I,EAAeqK,GAAiBxB,GAAY,EAG9C7I,EAAeqK,GAAiBA,GAAmB,CAAC,GAEvD,IAEJ,KAE6B,OAAvBhH,KAAKF,eACdtJ,OAAOqQ,KAAK7G,KAAK2G,oBAAoBtE,SAASyE,IAC5C,GAAgD,kBAA5C9G,KAAK2G,mBAAmBG,GAAa,GAAwB,CAC/D,MAAM5Q,EAAQ8J,KAAK2G,mBAAmBG,GAAa,GACnDpS,EAAS,YAAYoS,iCAA2C5Q,2BAChE8J,KAAKkC,iBAAiB4E,GAAazE,SAAQ,EAAEuB,EAAcd,MACzD,GAA0B,WAAtB9C,KAAKD,aAA2B,EACZ,CACpB,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,KAEK+C,GAAMT,SAASmB,IAC3B,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAC5D9O,EACE,sCAAsCsS,EAAkB,cACtDpD,EAAe,iBACDJ,EAAY,MAG9B5G,EAAeoK,GAAmB9Q,EAElC,IAAK,IAAIsP,EAAW,EAAGA,EAAW5I,EAAe3I,OAAQuR,IACvD7I,EAAeqK,GAAiBxB,GAAY,EAG9C7I,EAAeqK,GAAiBA,GAAmB,CAAC,GAEpE,MAAmB,GAA0B,cAAtBhH,KAAKD,aAA8B,EACtB,CACpB,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,KAEE+C,GAAMT,SAASmB,IAC3B,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAC5D9O,EACE,sCAAsCsS,EAAkB,cACtDpD,EAAe,iBACDJ,EAAY,MAG9B5G,EAAeoK,GAAmB9Q,EAElC,IAAK,IAAIsP,EAAW,EAAGA,EAAW5I,EAAe3I,OAAQuR,IACvD7I,EAAeqK,GAAiBxB,GAAY,EAG9C7I,EAAeqK,GAAiBA,GAAmB,CAAC,GAEvD,IAEJ,IAGN,CAOD,0CAAAyC,CAA2CvC,EAAoBC,GAClC,OAAvBnH,KAAKF,cACPtJ,OAAOqQ,KAAK7G,KAAK2G,oBAAoBtE,SAASyE,IAC5C,GAAgD,kBAA5C9G,KAAK2G,mBAAmBG,GAAa,GAAwB,CAC/D,MAAM5Q,EAAQ8J,KAAK2G,mBAAmBG,GAAa,GACnDpS,EAAS,YAAYoS,iCAA2C5Q,2BAChE8J,KAAKkC,iBAAiB4E,GAAazE,SAAQ,EAAEuB,EAAcd,MACzD,GAA0B,WAAtB9C,KAAKD,aAA2B,EACZ,CACpB,EAAG,CAAC,GACJ,EAAG,CAAC,KAEQ+C,GAAMT,SAASmB,IAC3B,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAC5D9O,EACE,sCAAsCsS,EAAkB,cACtDpD,EAAe,iBACDJ,EAAY,MAE9B0D,EAAmBF,GAAmB,EACtCG,EAAeH,GAAmB9Q,CAAK,GAEvD,MAAmB,GAA0B,cAAtB8J,KAAKD,aAA8B,EACtB,CACpB,EAAG,CAAC,GACJ,EAAG,CAAC,KAEQ+C,GAAMT,SAASmB,IAC3B,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAC5D9O,EACE,sCAAsCsS,EAAkB,cACtDpD,EAAe,iBACDJ,EAAY,MAE9B0D,EAAmBF,GAAmB,EACtCG,EAAeH,GAAmB9Q,CAAK,GAE1C,IAEJ,KAE6B,OAAvB8J,KAAKF,eACdtJ,OAAOqQ,KAAK7G,KAAK2G,oBAAoBtE,SAASyE,IAC5C,GAAgD,kBAA5C9G,KAAK2G,mBAAmBG,GAAa,GAAwB,CAC/D,MAAM5Q,EAAQ8J,KAAK2G,mBAAmBG,GAAa,GACnDpS,EAAS,YAAYoS,iCAA2C5Q,2BAChE8J,KAAKkC,iBAAiB4E,GAAazE,SAAQ,EAAEuB,EAAcd,MACzD,GAA0B,WAAtB9C,KAAKD,aAA2B,EACZ,CACpB,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,GACP,EAAG,CAAC,EAAG,KAEK+C,GAAMT,SAASmB,IAC3B,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAC5D9O,EACE,sCAAsCsS,EAAkB,cACtDpD,EAAe,iBACDJ,EAAY,MAE9B0D,EAAmBF,GAAmB,EACtCG,EAAeH,GAAmB9Q,CAAK,GAEvD,MAAmB,GAA0B,cAAtB8J,KAAKD,aAA8B,EACtB,CACpB,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,GACV,EAAG,CAAC,EAAG,EAAG,KAEE+C,GAAMT,SAASmB,IAC3B,MAAMwD,EAAkBhH,KAAK2D,IAAIC,GAAcJ,GAAa,EAC5D9O,EACE,sCAAsCsS,EAAkB,cACtDpD,EAAe,iBACDJ,EAAY,MAE9B0D,EAAmBF,GAAmB,EACtCG,EAAeH,GAAmB9Q,CAAK,GAE1C,IAEJ,IAGN,ECzNI,SAASwT,EACdnE,EACAoB,EACA3J,EACA2M,GAEAlV,EAAS,iDAGT,IAAImV,EAAqB,EAAID,EArBA,IAsB7BjV,EAAS,uBAAuBkV,KAChClV,EAAS,0BAA0BiV,KAGnC,MAAMtG,kBACJA,EAAiBW,kBACjBA,EAAiBL,IACjBA,EAAGzB,iBACHA,EAAgBkD,cAChBA,EAAatF,cACbA,EAAaC,aACbA,GACEwF,EAGEqD,EAAUtD,EAAcC,IACxB3I,eACJA,EAAcD,eACdA,EAAcgJ,iBACdA,EAAgBF,eAChBA,EAAcX,YACdA,EAAWC,aACXA,EAAYa,SACZA,GACEgD,EAGJ,IAAK,IAAIhF,EAAe,EAAGA,EAAewB,EAAexB,IAAgB,CAEvE,IAAK,IAAIqC,EAAiB,EAAGA,EAAiBL,EAAUK,IAEtDN,EAAiBM,GAAkBtC,EAAIC,GAAcqC,GAAkB,EAIzE,IAAK,IAAI4C,EAAmB,EAAGA,EAAmB/D,EAAY7Q,OAAQ4U,IAEpE,GAAsB,OAAlB/I,EAAwB,CAE1BlL,SAAS,6CAGT,IAAIoT,EAA+BvC,EAAexF,kBAAkB6E,EAAY+D,IAGhF,MAAMC,EAAgBjD,EAA8B,CAClDzF,cAAe4H,EAA6B5H,cAC5CC,sBAAuB2H,EAA6B3H,sBACpDgD,oBACAsC,mBACAC,cAIIM,YAAEA,EAAWC,oBAAEA,GAAwB2C,EACvBd,EAA6B5H,cAGnD,IAAIyJ,EAAiB,EACrB,IAAK,IAAI5D,EAAiB,EAAGA,EAAiBL,EAAUK,IACtD4D,GACE7M,EAAe2I,EAAiBM,IAAmBE,EAAoBF,GAI3E,IAAK,IAAI8C,EAAkB,EAAGA,EAAkBnD,EAAUmD,IAAmB,CACnDpD,EAAiBoD,GAIzC,IAAK,IAAIb,EAAkB,EAAGA,EAAkBtC,EAAUsC,IAChCvC,EAAiBuC,EAI5C,CACF,MAEI,GAAsB,OAAlBpI,EACP,IAAK,IAAIoJ,EAAmB,EAAGA,EAAmBpE,EAAY7Q,OAAQiV,IAAoB,CAExF,IAAIlB,EAA+BvC,EAAexF,kBAChD6E,EAAY+D,GACZ/D,EAAYoE,IAId,MAAMJ,EAAgB1C,EAA8B,CAClDhG,cAAe4H,EAA6B5H,cAC5CC,sBAAuB2H,EAA6B3H,sBACpDC,sBAAuB0H,EAA6B1H,sBACpD+C,oBACAW,oBACA2B,mBACAC,cAIIM,YAAEA,EAAWC,oBAAEA,EAAmBM,oBAAEA,GAAwBqC,EAC5D1I,EAAgB4H,EAA6B5H,cAGnD,IAAIyJ,EAAiB,EACjBC,EAAiB,EACrB,IAAK,IAAI7D,EAAiB,EAAGA,EAAiBL,EAAUK,IACtD4D,GACE7M,EAAe2I,EAAiBM,IAAmBE,EAAoBF,GACzE6D,GACE9M,EAAe2I,EAAiBM,IAAmBQ,EAAoBR,GAI3E,IAAK,IAAI8C,EAAkB,EAAGA,EAAkBnD,EAAUmD,IAAmB,CAC3E,IAAIC,EAAoBrD,EAAiBoD,GAGzCnM,EAAeoM,IACbY,EACE7E,EAAa8D,GACb9D,EAAamE,GACbhD,EACAC,EAAoB4C,GACpBc,EACFD,EACE7E,EAAa8D,GACb9D,EAAamE,GACbhD,EACAO,EAAoBsC,GACpBe,EAG0B,IAA1BH,IACF/M,EAAeoM,IACbW,GACC5E,EAAa8D,GACZ9D,EAAamE,GACbhD,EACA9F,EAAc2I,GACd7U,KAAKC,KAAK0V,GAAkB,EAAIC,GAAkB,GAClD/E,EAAa8D,GACX9D,EAAamE,GACbhD,EACA9F,EAAc2I,KAGtB,IAAK,IAAIb,EAAkB,EAAGA,EAAkBtC,EAAUsC,IAAmB,CAC3E,IAAIe,EAAoBtD,EAAiBuC,GAGzCvL,EAAeqM,GAAmBC,KAC/BW,EACD7E,EAAa8D,GACb9D,EAAamE,GACbhD,GACCC,EAAoB4C,GAAmB5C,EAAoB+B,GAC1DzB,EAAoBsC,GAAmBtC,EAAoByB,IAGjC,IAA1ByB,IACFhN,EAAeqM,GAAmBC,IAChCU,IAEIzD,EACA2D,EACAzJ,EAAc2I,GACdhE,EAAa8D,GACb9D,EAAamE,GAEbhV,KAAKC,KAAK0V,GAAkB,EAAIC,GAAkB,EAAI,OACxD3D,EAAoB+B,GACtByB,GACIzD,EACA4D,EACA1J,EAAc2I,GACdhE,EAAa8D,GACb9D,EAAamE,GACbhV,KAAKC,KAAK0V,GAAkB,EAAIC,GAAkB,EAAI,OACxDrD,EAAoByB,GAE3B,CACF,CACF,CAGN,CAeD,OAZkC,IAAIqB,EACpC5C,EACAzE,EACAyB,EACA7D,EACAC,GAIwByJ,kCAAkC5M,EAAgBD,GAC5ElI,EAAS,+CAEF,CACLkI,iBACAC,iBAEJ,CAgBO,SAASmN,GAA8BnG,aAC5CA,EAAYD,IACZA,EAAG4B,SACHA,EAAQE,eACRA,EAAcmD,QACdA,EAAO5L,eACPA,EAAc2M,sBACdA,IAGA,MAAM7E,YAAEA,EAAWC,aAAEA,EAAYa,SAAEA,GAAagD,GAC1CvF,kBAAEA,EAAiBW,kBAAEA,EAAiBlE,cAAEA,GAAkByF,EAGhE,IAAIqE,EAAqB,EAAID,EA/PA,IAkQ7B,MAAMrB,EAAsBzM,MAAM+J,GAC/BzJ,OACAxE,KAAI,IAAMkE,MAAM+J,GAAUzJ,KAAK,KAC5BoM,EAAsB1M,MAAM+J,GAAUzJ,KAAK,GAG3CkN,EAAMxN,MAAM+J,GACZD,EAAmB9J,MAAM+J,GAC/B,IAAK,IAAIK,EAAiB,EAAGA,EAAiBL,EAAUK,IACtDoD,EAAIpD,GAAkB/R,KAAKuK,IAAIkF,EAAIC,GAAcqC,IACjDN,EAAiBM,GAAkB/R,KAAKuK,IAAIkF,EAAIC,GAAcqC,IAAmB,EAInF,IAAK,IAAI4C,EAAmB,EAAGA,EAAmB/D,EAAY7Q,OAAQ4U,IAEpE,GAAsB,OAAlB/I,EAAwB,CAE1BlL,SAAS,6CAGT,IAAIoT,EAA+BvC,EAAexF,kBAAkB6E,EAAY+D,IAGhF,MAAMC,EAAgBjD,EAA8B,CAClDzF,cAAe4H,EAA6B5H,cAC5CC,sBAAuB2H,EAA6B3H,sBACpDgD,oBACAsC,mBACAC,cAIIM,YAAEA,EAAWC,oBAAEA,GAAwB2C,EACvBd,EAA6B5H,cAGnD,IAAIyJ,EAAiB,EACrB,IAAK,IAAI5D,EAAiB,EAAGA,EAAiBL,EAAUK,IACtD4D,GACE7M,EAAe2I,EAAiBM,IAAmBE,EAAoBF,GAI3E,IAAK,IAAI8C,EAAkB,EAAGA,EAAkBnD,EAAUmD,IAAmB,CACnDpD,EAAiBoD,GAIzC,IAAK,IAAIb,EAAkB,EAAGA,EAAkBtC,EAAUsC,IAChCvC,EAAiBuC,EAI5C,CAEP,MAAW,GAAsB,OAAlBpI,EACT,IAAK,IAAIoJ,EAAmB,EAAGA,EAAmBpE,EAAY7Q,OAAQiV,IAAoB,CAExF,MAAM9I,cAAEA,EAAaC,sBAAEA,EAAqBC,sBAAEA,GAC5CmF,EAAexF,kBAAkB6E,EAAY+D,GAAmB/D,EAAYoE,KAGxEhD,YAAEA,EAAWC,oBAAEA,EAAmBM,oBAAEA,GAAwBL,EAA8B,CAC9FhG,gBACAC,wBACAC,wBACA+C,oBACAW,oBACA2B,mBACAC,aAIF,IAAIiE,EAAiB,EACjBC,EAAiB,EACrB,IAAK,IAAI7D,EAAiB,EAAGA,EAAiBL,EAAUK,IACtD4D,GACE7M,EAAe2I,EAAiBM,IAAmBE,EAAoBF,GACzE6D,GACE9M,EAAe2I,EAAiBM,IAAmBQ,EAAoBR,GAI3E,IAAK,IAAI8C,EAAkB,EAAGA,EAAkBnD,EAAUmD,IAAmB,CACnDpD,EAAiBoD,GAEzCR,EAAoBQ,IAClBa,EACE7E,EAAa8D,GACb9D,EAAamE,GACbhD,EACAC,EAAoB4C,GACpBc,EACFD,EACE7E,EAAa8D,GACb9D,EAAamE,GACbhD,EACAO,EAAoBsC,GACpBe,EAG0B,IAA1BH,IACFpB,EAAoBQ,IAClBY,GACC5E,EAAa8D,GACZ9D,EAAamE,GACbhD,EACA9F,EAAc2I,GACd7U,KAAKC,KAAK0V,GAAkB,EAAIC,GAAkB,GAClD/E,EAAa8D,GACX9D,EAAamE,GACbhD,EACA9F,EAAc2I,KAGtB,IAAK,IAAIb,EAAkB,EAAGA,EAAkBtC,EAAUsC,IAExDI,EAAoBS,GAAiBb,IACnC0B,EACA7E,EAAa8D,GACb9D,EAAamE,GACbhD,GACCC,EAAoB4C,GAAmB5C,EAAoB+B,GAC1DzB,EAAoBsC,GAAmBtC,EAAoByB,IAGjC,IAA1ByB,IACFrB,EAAoBS,GAAiBb,IACnCyB,IAEIzD,EACA2D,EACAzJ,EAAc2I,GACdhE,EAAa8D,GACb9D,EAAamE,GAEbhV,KAAKC,KAAK0V,GAAkB,EAAIC,GAAkB,EAAI,OACxD3D,EAAoB+B,GACtByB,GACIzD,EACA4D,EACA1J,EAAc2I,GACdhE,EAAa8D,GACb9D,EAAamE,GACbhV,KAAKC,KAAK0V,GAAkB,EAAIC,GAAkB,EAAI,OACxDrD,EAAoByB,GAG7B,CACF,CAIL,MAAO,CAAEI,sBAAqBC,sBAAqBc,MACrD,CC7ZA,MAAMW,EAAc,CAAA,EACdC,EAAe,CAAA,EACfC,EAAc,CAAEC,oBAAqB,GACrCC,EAAe,CAAA,EACrB,IAAI3E,EAUG,SAAS4E,EAAiBC,EAAe/E,EAAUoB,EAAoB9J,EAAU,CAAA,GAEtF,MAAM+L,EAAUtD,EAAcC,GACxBF,EAAaE,EAASlC,kBAAkBpP,OACxCsW,EAAchF,EAASH,eA6H/B,SAAiCQ,EAAU2E,GAEzCP,EAAY1I,eAAiBzF,MAAM0O,GAChCpO,OACAxE,KAAI,IAAMkE,MAAM+J,GAAUzJ,KAAK,KAClC6N,EAAY9C,mBAAqBrL,MAAM+J,GAAUzJ,KAAK,GACtD6N,EAAY7C,eAAiBtL,MAAM+J,GAAUzJ,KAAK,GAClD6N,EAAYQ,qBAAuB3O,MAAM+J,GAAUzJ,KAAK,GACxD6N,EAAYhN,eAAiBnB,MAAM+J,GAAUzJ,KAAK,GAClD6N,EAAYS,aAAe5O,MAAM0O,GAAapO,KAAK,GACnD6N,EAAYU,YAAc7O,MAAM0O,GAAapO,KAAK,GAGlD8N,EAAaU,UAAY,EACzBV,EAAa5E,WAAaO,EAC1BqE,EAAaW,mBAAqB,EAClCX,EAAaY,gBAAkBhP,MAAM0O,GAAapO,KAAK,GACvD8N,EAAaa,YAAc,EAG3B,MAAMC,EAAa7W,KAAKsK,IAAIoH,EAAU,KACtCqE,EAAae,qBAAuBnP,MAAMkP,GAAY5O,KAAK,GAC3D8N,EAAagB,eAAiB,EAG9Bf,EAAY5B,oBAAsBzM,MAAM+J,GACrCzJ,OACAxE,KAAI,IAAMkE,MAAM+J,GAAUzJ,KAAK,KAClC+N,EAAYC,oBAAsB,EAGlC,MAAMe,EAaR,SAA2BtF,EAAU2E,GACnC,MAAMY,EAAqBjX,KAAKsK,IAAItK,KAAKkX,KAAKlX,KAAKC,KAAKoW,IAAgB3E,EAAqB,EAAXA,GAClF,OAAOuF,EAAqBZ,CAC9B,CAhBoBc,CAAkBzF,EAAU2E,GAC9CH,EAAakB,YAAczP,MAAMqP,GAAW/O,KAAK,GACjDiO,EAAamB,cAAgB1P,MAAMkP,GAAY5O,KAAK,GACpDiO,EAAaoB,SAAW3P,MAAMkP,GAAY5O,KAAK,GAC/CiO,EAAaqB,UAAY5P,MAAMqP,GAAW/O,KAAK,EACjD,CA7JEuP,CAHiB9C,EAAQhD,SAGS2E,GAGlC9V,EAAS,mCACTF,QAAQ4I,KAAK,iBAGbsI,EAAiB,IAAI5F,EAAe,CAClCC,cAAeyF,EAASzF,cACxBC,aAAcwF,EAASxF,eAIzB,IAAK,IAAI6D,EAAe,EAAGA,EAAe2B,EAASH,cAAexB,IAChE,IAAK,IAAIJ,EAAY,EAAGA,EAAYoF,EAAQhD,SAAUpC,IACpDwG,EAAY1I,eAAesC,GAAcJ,GAAa+B,EAAS5B,IAAIC,GAAcJ,GAMrF,IAAK,IAAIA,EAAY,EAAGA,EAAY+B,EAASlC,kBAAkBpP,OAAQuP,IACrEwG,EAAY9C,mBAAmB1D,GAAa,EAC5CwG,EAAY7C,eAAe3D,GAAa,EAI1C,IAAImI,EAEArB,IAAkBlB,GACpBuC,EAAqC,IAAIjF,EACvCC,EACApB,EAASrD,iBACTqD,EAAS5B,IACT4B,EAASzF,cACTyF,EAASxF,cAGX4L,EAAmC1E,0CACjC+C,EAAY9C,mBACZ8C,EAAY7C,iBAGLmD,IAAkBP,IAC3B4B,EAAqC,IAAIpC,EACvC5C,EACApB,EAASrD,iBACTqD,EAAS5B,IACT4B,EAASzF,cACTyF,EAASxF,cAGX4L,EAAmClC,2CACjCO,EAAY9C,mBACZ8C,EAAY7C,iBAIhB,IAAK,IAAI3D,EAAY,EAAGA,EAAY+B,EAASlC,kBAAkBpP,OAAQuP,IACrEwG,EAAYQ,qBAAqBhH,GAAa,EAGhDyG,EAAa5E,WAAaE,EAASlC,kBAAkBpP,OACrDgW,EAAaU,UAAY,EACzBV,EAAaW,mBAAqB,EAClCX,EAAaa,YAAc,EAE3B,IAAK,IAAIlH,EAAe,EAAGA,EAAe2B,EAASH,cAAexB,IAChEqG,EAAaY,gBAAgBjH,GAAgBgF,EAAQhD,SAIvDqE,EAAa2B,sBAAwB/O,EAAQG,eAC7CiN,EAAaN,sBAAwB9M,EAAQ8M,sBAkM/C,SAA6BpE,EAAUqD,EAASO,EAA2BmB,GAEzE,MAAMlF,EAAgBG,EAASH,cACzBQ,EAAWL,EAASlC,kBAAkBpP,OACtC8W,EAAa7W,KAAKsK,IAAIoH,EAAUqE,EAAae,qBAAqB/W,QACxE,IAaI4X,EAbAC,EAAmBjQ,MAAM+M,EAAQhD,UAAUzJ,KAAK,GAChD4P,EAAiBlQ,MAAM+M,EAAQhD,UAAUzJ,KAAK,GAC9C6P,EAAanQ,MAAMkP,GAAY5O,KAAK,GACpC8P,EAAkBpQ,MAAMkP,GAAY5O,KAAK,GACzC+P,EAAqBrQ,MAAMkP,GAAY5O,KAAK,GAC5CgQ,EAAetQ,MAAMkP,GAAY5O,KAAK,GACtCiQ,EAAcvQ,MAAMkP,GAAY5O,KAAK,GACrCkQ,EAAcxQ,MAAMkP,GACrB5O,OACAxE,KAAI,IAAMkE,MAAMkP,GAAY5O,KAAK,KAChCmQ,EAAezQ,MAAM+J,GAAUzJ,KAAK,GACpCoQ,EAAkB1Q,MAAM+J,GAAUzJ,KAAK,GACvCqQ,EAAsB3Q,MAAM+J,GAAUzJ,KAAK,GAG3CsQ,EAAmB,EACvBxC,EAAaU,YACb,IAAI+B,EAAiB,EACjBC,EAAa,EACjBzC,EAAYC,oBAAsB,EAElC,IAAK,IAAI3G,EAAY,EAAGA,EAAYyG,EAAa5E,WAAY7B,IAC3D8I,EAAa9I,GAAa,EAC1B+I,EAAgB/I,GAAa,EAG/B,GAAwC,IAApCyG,EAAaW,mBAA0B,CAEzC,IAAK,IAAIpH,EAAY,EAAGA,EAAYyG,EAAa5E,WAAY7B,IAC3DgJ,EAAoBhJ,GAAa,EAGnC,IAAK,IAAII,EAAe,EAAGA,EAAewB,EAAexB,IAAgB,CACvE,IAAIgJ,EAAsBxH,EAAgBxB,EAAe,EACzD,IACE,IAAIqC,EAAiB,EACrBA,EAAiBgE,EAAaY,gBAAgB+B,GAC9C3G,IACA,CACA,IAAIe,EAAkBgD,EAAY1I,eAAesL,GAAqB3G,GACrB,IAA7CuG,EAAoBxF,EAAkB,KACxCwF,EAAoBxF,EAAkB,GAAK,EAC3CgD,EAAY1I,eAAesL,GAAqB3G,IAC7C+D,EAAY1I,eAAesL,GAAqB3G,GAEtD,CACF,CACF,CAEDgE,EAAaW,mBAAqB,EAClC,IAAIiC,EAAc,EACdC,EAAW,EAEf,IAAK,IAAI9Y,EAAI,EAAGA,EAAI+W,EAAY/W,IAC9B,IAAK,IAAIsK,EAAI,EAAGA,EAAIyM,EAAYzM,IAC9B+N,EAAY/N,GAAGtK,GAAK,EAIxB,OAAa,CAEX,IAAI+Y,GAAY,EACZC,EAAkB,EAClBC,EAAoB,EAOxB,GALI/C,EAAYC,oBAAsB/E,IACpC8E,EAAYC,sBACZ4C,EAAYG,EAA4B3H,EAAUqD,EAASO,EAA2BmB,IAGpFyC,EAAW,CACb,MAAMI,EAAiBjD,EAAYC,oBACnC6C,EAAkB/C,EAAaY,gBAAgBsC,EAAiB,GAChEF,EAAoBhD,EAAaY,gBAAgBsC,EAAiB,GAElE,IAAK,IAAIlH,EAAiB,EAAGA,EAAiBgH,EAAmBhH,IAAkB,CACjF,IACImH,EAqBAC,EAtBArG,EAAkBgD,EAAY1I,eAAe6L,EAAiB,GAAGlH,GAGrE,GAAoB,IAAhB4G,EACFA,IACAf,EAAiB7F,GAAkB4G,EACnCzC,EAAamB,cAAcsB,EAAc,GAAK7F,MACzC,CACL,IAAKoG,EAAc,EAAGA,EAAcP,GAC9B3Y,KAAKuK,IAAIuI,KAAqB9S,KAAKuK,IAAI2L,EAAamB,cAAc6B,IADvBA,KAI7CA,IAAgBP,GAClBA,IACAf,EAAiB7F,GAAkB4G,EACnCzC,EAAamB,cAAcsB,EAAc,GAAK7F,IAE9C8E,EAAiB7F,GAAkBmH,EAAc,EACjDhD,EAAamB,cAAc6B,GAAepG,EAE7C,CAGD,GAAiB,IAAb8F,EACFA,IACAf,EAAe9F,GAAkB6G,EACjCd,EAAWc,EAAW,GAAK9F,MACtB,CACL,IAAKqG,EAAW,EAAGA,EAAWP,GACxB5Y,KAAKuK,IAAIuI,KAAqB9S,KAAKuK,IAAIuN,EAAWqB,IADhBA,KAIpCA,IAAaP,GACfA,IACAf,EAAe9F,GAAkB6G,EACjCd,EAAWc,EAAW,GAAK9F,IAE3B+E,EAAe9F,GAAkBoH,EAAW,EAC5CrB,EAAWqB,GAAYrG,EAE1B,CACF,CAED,GAAI8F,EAAW/B,GAAc8B,EAAc9B,EAEzC,YADAnW,EAAS,sCAIX,IAAK,IAAI0Y,EAAmB,EAAGA,EAAmBL,EAAmBK,IAAoB,CACvF,IAAIC,EAAmBzB,EAAiBwB,GACxC,IAAK,IAAIE,EAAgB,EAAGA,EAAgBR,EAAiBQ,IAAiB,CAE5EnB,EADoBN,EAAeyB,GACP,GAAGD,EAAmB,IAChDrD,EAAY5B,oBAAoBkF,GAAeF,EAClD,CACF,CACF,CAGD,IAAIG,EAAuB,EAC3B,IAAK,IAAIL,EAAc,EAAGA,EAAcP,EAAaO,IAC/ChD,EAAamB,cAAc6B,GAAe,IAC5ClB,EAAmBuB,GAAwBL,EAAc,EACzDK,KAIJ,IAAIC,EAAsB,EACtBC,EAAoB,EACxB,IAAK,IAAIN,EAAW,EAAGA,EAAWP,EAAUO,IAAY,CACtD,IAAIrG,EAAkBgF,EAAWqB,GACjC,GAAIrG,EAAkB,EAAG,CACvBiF,EAAgB0B,GAAqBN,EAAW,EAChDM,IACA,IAAIC,EAAoB1Z,KAAKuK,IAAIuI,GAC6B,IAA1DgD,EAAY9C,mBAAmB0G,EAAoB,KACrDzB,EAAauB,GAAuBL,EAAW,EAC/CK,IACA1D,EAAY9C,mBAAmB0G,EAAoB,GAAK,EACxD5D,EAAYQ,qBAAqBoD,EAAoB,GACnD5D,EAAY7C,eAAeyG,EAAoB,GAEpD,CACF,CAED,GAAIF,EAAsB,EACxB,IAAK,IAAIG,EAAmB,EAAGA,EAAmBH,EAAqBG,IAAoB,CACzF,IAAIR,EAAWlB,EAAa0B,GAAoB,EAC5C7G,EAAkB9S,KAAKuK,IAAIuN,EAAWqB,IAC1C,IAAK,IAAID,EAAc,EAAGA,EAAcP,EAAaO,IAAe,CAClEf,EAAYgB,GAAUD,GAAe,EACblZ,KAAKuK,IAAI2L,EAAamB,cAAc6B,MAClCpG,IAAiBqF,EAAYgB,GAAUD,GAAe,EACjF,CACF,CAGH,GAAIK,EAAuBd,GAAczC,EAAYC,oBAAsB/E,EAAe,CACxF,GAA6B,IAAzBqI,EAEF,YADA7Y,EAAS,oCAIX,IAAIkZ,EAAgB7B,EAAgB,GAChC8B,EAAmB7B,EAAmB,GACtC8B,EAAa3B,EAAYyB,EAAgB,GAAGC,EAAmB,GAEnE,GAAI7Z,KAAKuK,IAAIuP,GAAc,KAAM,CAC/BA,EAAa,EACb,IAAK,IAAIZ,EAAc,EAAGA,EAAcK,EAAsBL,IAAe,CAC3E,IAAIa,EAAkB/B,EAAmBkB,GACzC,IAAK,IAAIC,EAAW,EAAGA,EAAWM,EAAmBN,IAAY,CAC/D,IAAIa,EAAejC,EAAgBoB,GAC/Bc,EAAY9B,EAAY6B,EAAe,GAAGD,EAAkB,GAC5D/Z,KAAKuK,IAAI0P,GAAaja,KAAKuK,IAAIuP,KACjCA,EAAaG,EACbJ,EAAmBE,EACnBH,EAAgBI,EAEnB,CACF,CACF,CAED,IAAIE,EAAsBla,KAAKuK,IAAIuN,EAAW8B,EAAgB,IAC9DjC,EAAyB3X,KAAKuK,IAAI2L,EAAamB,cAAcwC,EAAmB,IAChF,IAAIM,EACFD,EACAvC,EACAS,EAAa8B,EAAsB,GACnC7B,EAAgBV,EAAyB,GAC3C5B,EAAaa,YACVb,EAAaa,YAAckD,IAAe,IAAMK,EAAqBna,KAAKuK,IAAIuP,GAEjF,IAAK,IAAIxK,EAAY,EAAGA,EAAYyG,EAAa5E,WAAY7B,IACvDA,GAAa4K,GAAqB9B,EAAa9I,KAC/CA,GAAaqI,GAAwBU,EAAgB/I,KAS3D,GANItP,KAAKuK,IAAIuP,GAAc,OACzBpZ,EACE,2DAA2DsV,EAAYC,4CAA4CiE,6BAA+CvC,iBAAsCmC,KAIzL,IAAfA,EAAkB,OAEtB,IAAK,IAAIZ,EAAc,EAAGA,EAAcP,EAAaO,IACnDhD,EAAaoB,SAAS4B,GAAef,EAAYyB,EAAgB,GAAGV,GAAeY,EAGrF,IAAIM,EAAgBtE,EAAYQ,qBAAqB4D,EAAsB,GAAKJ,EAIhF,GAHAhE,EAAYQ,qBAAqB4D,EAAsB,GAAKE,EAC5DlC,EAAY0B,EAAgB,GAAKE,EAE7BF,EAAgB,EAClB,IAAK,IAAIT,EAAW,EAAGA,EAAWS,EAAgB,EAAGT,IAAY,CAC/D,IAAIkB,EAAiBra,KAAKuK,IAAIuN,EAAWqB,IACrCmB,EAAoBnC,EAAYgB,GAAUU,EAAmB,GAEjE,GADA3B,EAAYiB,GAAYmB,EACpBT,EAAmB,GAA2B,IAAtBS,EAC1B,IAAK,IAAIpB,EAAc,EAAGA,EAAcW,EAAmB,EAAGX,IAC5Df,EAAYgB,GAAUD,IAAgBoB,EAAoBpE,EAAaoB,SAAS4B,GAGpF,GAAIW,EAAmBlB,EACrB,IAAK,IAAIO,EAAcW,EAAkBX,EAAcP,EAAaO,IAClEf,EAAYgB,GAAUD,EAAc,GAClCf,EAAYgB,GAAUD,GAAeoB,EAAoBpE,EAAaoB,SAAS4B,GAGrFpD,EAAYQ,qBAAqB+D,EAAiB,IAAMC,EAAoBF,CAC7E,CAGH,GAAIR,EAAgBhB,EAClB,IAAK,IAAIO,EAAWS,EAAeT,EAAWP,EAAUO,IAAY,CAClE,IAAIkB,EAAiBra,KAAKuK,IAAIuN,EAAWqB,IACrCmB,EAAoBnC,EAAYgB,GAAUU,EAAmB,GAEjE,GADA3B,EAAYiB,GAAYmB,EACpBT,EAAmB,EACrB,IAAK,IAAIX,EAAc,EAAGA,EAAcW,EAAmB,EAAGX,IAC5Df,EAAYgB,EAAW,GAAGD,GACxBf,EAAYgB,GAAUD,GAAeoB,EAAoBpE,EAAaoB,SAAS4B,GAGrF,GAAIW,EAAmBlB,EACrB,IAAK,IAAIO,EAAcW,EAAkBX,EAAcP,EAAaO,IAClEf,EAAYgB,EAAW,GAAGD,EAAc,GACtCf,EAAYgB,GAAUD,GAAeoB,EAAoBpE,EAAaoB,SAAS4B,GAGrFpD,EAAYQ,qBAAqB+D,EAAiB,IAAMC,EAAoBF,CAC7E,CAGH,IAAK,IAAIta,EAAI,EAAGA,EAAI8Y,EAAU9Y,IAC5BoW,EAAaqB,UAAUiB,EAAiB1Y,EAAI,GAAKoY,EAAYpY,GAE/D0Y,GAAkBI,EAElB,IAAK,IAAI9Y,EAAI,EAAGA,EAAI8Y,EAAU9Y,IAC5BoW,EAAaqB,UAAUiB,EAAiB1Y,EAAI,GAAKgY,EAAWhY,GAE9D0Y,GAAkBI,EAElB1C,EAAaqB,UAAUiB,EAAiB,GAAKoB,EAC7CpB,IAEA,IAAK,IAAI1Y,EAAI,EAAGA,EAAI6Y,EAAa7Y,IAC/BoW,EAAakB,YAAYmB,EAAmB,EAAIzY,GAAKoW,EAAaoB,SAASxX,GAE7EyY,GAAoBI,EAEpB,IAAK,IAAI7Y,EAAI,EAAGA,EAAI6Y,EAAa7Y,IAC/BoW,EAAakB,YAAYmB,EAAmB,EAAIzY,GAAKoW,EAAamB,cAAcvX,GAElFyY,GAAoBI,EAEpBzC,EAAakB,YAAYmB,EAAmB,GAAK2B,EACjDhE,EAAakB,YAAYmB,GAAoBI,EAC7CzC,EAAakB,YAAYmB,EAAmB,GAAKsB,EACjD3D,EAAakB,YAAYmB,EAAmB,GAAKuB,EACjDvB,GAAoB,EAEpB,IAAK,IAAIY,EAAW,EAAGA,EAAWP,EAAUO,IAC1ChB,EAAYgB,GAAUR,EAAc,GAAK,EAG3C,IAAK,IAAIO,EAAc,EAAGA,EAAcP,EAAaO,IACnDf,EAAYS,EAAW,GAAGM,GAAe,EAI3C,GADAP,IACIkB,EAAmBlB,EAAc,EACnC,IAAK,IAAIO,EAAcW,EAAmB,EAAGX,EAAcP,EAAaO,IACtEhD,EAAamB,cAAc6B,GAAehD,EAAamB,cAAc6B,EAAc,GAKvF,GADAN,IACIgB,EAAgBhB,EAAW,EAC7B,IAAK,IAAIO,EAAWS,EAAgB,EAAGT,EAAWP,EAAUO,IAC1DrB,EAAWqB,GAAYrB,EAAWqB,EAAW,GAIjD,GAAIP,EAAW,GAAK5C,EAAYC,oBAAsB/E,EAAe,SAsBrE,GApBAyG,EAAyB3X,KAAKuK,IAAI2L,EAAamB,cAAc,IAC7DuC,EAAgB,EAChBE,EAAa3B,EAAY,GAAG,GAC5B+B,EAAsBla,KAAKuK,IAAIuN,EAAW,IAC1C+B,EAAmB,EACnBM,EACED,EACAvC,EACAS,EAAa8B,EAAsB,GACnC7B,EAAgBV,EAAyB,GAC3C5B,EAAaa,YACVb,EAAaa,YAAckD,IAAe,IAAMK,EAAqBna,KAAKuK,IAAIuP,GAEjF5D,EAAaoB,SAAS,GAAK,EACvBtX,KAAKuK,IAAIuP,GAAc,OACzBpZ,EACE,2DAA2DsV,EAAYC,4CAA4CiE,6BAA+CvC,iBAAsCmC,KAIzL,IAAfA,EAAkB,OAEtBhE,EAAYQ,qBAAqB4D,EAAsB,GACrDpE,EAAYQ,qBAAqB4D,EAAsB,GAAKJ,EAC9D5D,EAAakB,YAAYmB,EAAmB,GAAKrC,EAAaoB,SAAS,GACvEiB,IACArC,EAAakB,YAAYmB,EAAmB,GAAKrC,EAAamB,cAAc,GAC5EkB,IACArC,EAAakB,YAAYmB,EAAmB,GAAK2B,EACjDhE,EAAakB,YAAYmB,GAAoBI,EAC7CzC,EAAakB,YAAYmB,EAAmB,GAAKsB,EACjD3D,EAAakB,YAAYmB,EAAmB,GAAKuB,EACjDvB,GAAoB,EAEpBrC,EAAaqB,UAAUiB,EAAiB,GAAKN,EAAY,GACzDM,IACAtC,EAAaqB,UAAUiB,EAAiB,GAAKV,EAAW,GACxDU,IACAtC,EAAaqB,UAAUiB,EAAiB,GAAKoB,EAC7CpB,IAEAzC,EAAagB,eAAiBwB,EACC,IAA3BxC,EAAaU,WACfjW,EAAS,0CAA0C+X,KAGrDgC,EAAwBhC,GACxB,KACD,CACF,CACH,CA1jBEiC,CAAoBnJ,EAAUqD,EAAS+C,EAAoCrB,GAG3E,IAAK,IAAI9G,EAAY,EAAGA,EAAY+B,EAASlC,kBAAkBpP,OAAQuP,IACrEwG,EAAYhN,eAAewG,GAAayG,EAAae,qBAAqBxH,GAI5E,MAAMH,kBAAEA,EAAiBW,kBAAEA,GAAsBuB,EACjD,IAAK,IAAI/B,EAAY,EAAGA,EAAY+B,EAASlC,kBAAkBpP,OAAQuP,IACtC,OAA3B+B,EAASzF,cAEXpL,EACE,GAAG2O,EAAkBG,GAAWmL,cAAc,OAAO3E,EAAYhN,eAC/DwG,GACAmL,cAAc,MAIlBja,EACE,GAAG2O,EAAkBG,GAAWmL,cAAc,OAAO3K,EAAkBR,GAAWmL,cAChF,OACI3E,EAAYhN,eAAewG,GAAWmL,cAAc,MAKhEpa,QAAQoK,QAAQ,iBAChBlK,EAAS,8BAET,MAAQ4O,kBAAmBuL,EAAa5K,kBAAmB6K,GAAgBtJ,EAC3E,MAAO,CACLvI,eAAgBgN,EAAYhN,eAAejF,MAAM,EAAGsN,GACpDyJ,iBAAkB,CAChBzL,kBAAmBuL,EACnB5K,kBAAmB6K,GAGzB,CAqEA,SAAS3B,EAA4B3H,EAAUqD,EAASO,EAA2BmB,GACjF,MAAM1G,EAAesG,EAAYC,oBAAsB,EAGvD,GAAIvG,EAAe,GAAKA,GAAgB2B,EAASH,cAE/C,OADAxQ,EAAS,sCAAsCgP,oBAA+B2B,EAASH,mBAChF,EAIT,MAAMkD,oBAAEA,EAAmBC,oBAAEA,EAAmBc,IAAEA,GAAQiB,EAAc,CACtE1G,eACAD,IAAKqG,EAAY1I,eACjBiE,WACAE,eAAgBA,EAChBmD,UAEA5L,eAAgBiN,EAAa2B,sBAC7BjC,sBAAuBM,EAAaN,wBAItC,IAAIoF,EAA8BlT,MAAM+M,EAAQhD,UAC7CzJ,OACAxE,KAAI,IAAMkE,MAAM+M,EAAQhD,UAAUzJ,KAAK,KACtC6S,EAAyBnT,MAAM+M,EAAQhD,UAAUzJ,KAAK,GAG1D,GAAImO,IAAkBlB,EAA6B,CAEjD,IAAI6F,GAAwB,EAC5B,IAAK,MAAMnI,KAAevB,EAASrD,iBACjC,GACqE,eAAnEiH,EAA0BxC,mBAAmBG,KAAe,IAC5DvB,EAASrD,iBAAiB4E,GAAaoI,MAAK,EAAErN,EAAS6G,KAAO7G,IAAY+B,IAC1E,CACAqL,GAAwB,EACxB,KACD,CAIH,GAAIA,EAAuB,CACzB,MAAMnK,YAAEA,EAAWC,aAAEA,GAAiB6D,EAChCnJ,EAAS0J,EAA0Bd,wCACvCzE,EACA2B,EAASlC,kBACTkC,EAASvB,kBACTc,EACAC,EACAU,GAEFsJ,EAA8BtP,EAAO6I,oBACrC0G,EAAyBvP,EAAO8I,mBACjC,CAGF,CAGD,IAAK,IAAI4G,EAAa,EAAGA,EAAavG,EAAQhD,SAAUuJ,IACtD,IAAK,IAAIC,EAAa,EAAGA,EAAaxG,EAAQhD,SAAUwJ,IACtDlF,EAAY5B,oBAAoB6G,GAAYC,GAC1C9G,EAAoB6G,GAAYC,GAAcL,EAA4BI,GAAYC,GAK5F,IAAK,IAAInJ,EAAiB,EAAGA,EAAiB2C,EAAQhD,SAAUK,IAAkB,CAChF,MAAMe,EAAkBqC,EAAIpD,GAAkB,EAC9C+D,EAAYQ,qBAAqBxD,IAC/BuB,EAAoBtC,GAAkB+I,EAAuB/I,EAChE,CAED,OAAO,CACT,CA0YA,SAASwI,EAAwBhC,GAC/B,IAAK,IAAIjJ,EAAY,EAAGA,EAAYyG,EAAa5E,WAAY7B,IAC3DyG,EAAae,qBAAqBxH,GAAawG,EAAY7C,eAAe3D,GAG5E,IAAK,IAAI6L,EAAiB,EAAGA,GAAkBpF,EAAa5E,WAAYgK,IAAkB,CACxF5C,GAAoB,EACpB,IAAI2B,EAAsBhE,EAAakB,YAAYmB,EAAmB,GAClEI,EAAczC,EAAakB,YAAYmB,GACvCsB,EAAmB3D,EAAakB,YAAYmB,EAAmB,GAGnE,GAFiBrC,EAAakB,YAAYmB,EAAmB,GAEtC,IAAnB4C,EACF5C,IACArC,EAAamB,cAAc,GAAKnB,EAAakB,YAAYmB,EAAmB,GAC5EA,IACArC,EAAaoB,SAAS,GAAKpB,EAAakB,YAAYmB,EAAmB,OAClE,CACLA,GAAoBI,EACpB,IAAK,IAAIO,EAAc,EAAGA,EAAcP,EAAaO,IACnDhD,EAAamB,cAAc6B,GACzBhD,EAAakB,YAAYmB,EAAmB,EAAIW,GAEpDX,GAAoBI,EACpB,IAAK,IAAIO,EAAc,EAAGA,EAAcP,EAAaO,IACnDhD,EAAaoB,SAAS4B,GAAehD,EAAakB,YAAYmB,EAAmB,EAAIW,EAExF,CAED,IAAIvB,EAAyB3X,KAAKuK,IAAI2L,EAAamB,cAAcwC,EAAmB,IACpF,GAAI/D,EAAY9C,mBAAmB2E,EAAyB,GAAK,EAAG,SAEpE,IAAIyD,EAAmB,EACvBlF,EAAaoB,SAASuC,EAAmB,GAAK,EAC9C,IAAK,IAAIX,EAAc,EAAGA,EAAcP,EAAaO,IACnDkC,GACElF,EAAaoB,SAAS4B,GACtBnD,EAAae,qBAAqB9W,KAAKuK,IAAI2L,EAAamB,cAAc6B,IAAgB,GAG1FnD,EAAae,qBAAqBa,EAAyB,GACzDyD,EAAmBtF,EAAYQ,qBAAqB4D,EAAsB,GAE5EpE,EAAY9C,mBAAmB2E,EAAyB,GAAK,CAC9D,CAE8B,IAA3B5B,EAAaU,WACfjW,EAAS,oDAAoD+X,IACjE,CC3sBO,SAAS8C,EAAcC,EAAaC,EAAU,IACnD,IAAIC,EAAY,EACZzS,GAAY,EACZC,EAAa,EACbqG,EAAS,GACTvG,EAAiB,GACjBL,EAAiB,GACjBC,EAAiB,GAGrB,MAAME,cAAEA,EAAgB,IAAGC,UAAEA,EAAY,MAAS0S,EAGlD,IAAIpK,EAAaoK,EAAQlK,SAASlC,kBAAkBpP,OAGpD,IAAK,IAAID,EAAI,EAAGA,EAAIqR,EAAYrR,IAC9BuP,EAAOvP,GAAK,EACZgJ,EAAehJ,GAAK,EAQtB,IAJIyb,EAAQE,iBAAmBF,EAAQE,gBAAgB1b,SAAWoR,IAChErI,EAAiB,IAAIyS,EAAQE,kBAGxBzS,EAAaJ,IAAkBG,GAAW,CAE/C,IAAK,IAAIjJ,EAAI,EAAGA,EAAIgJ,EAAe/I,OAAQD,IACzCgJ,EAAehJ,GAAKsI,OAAOU,EAAehJ,IAAMsI,OAAOiH,EAAOvP,IAIhE,GAA6B,YAAzByb,EAAQ/S,aAA4B,CAOtC6G,EANsB8G,EACpBN,EACA0F,EAAQlK,SACRkK,EAAQ9I,mBACR,CAAE3J,iBAAgB2M,sBAAuB8F,EAAQ9F,wBAE5B3M,cAC7B,KAAW,GAEFL,iBAAgBC,kBAAmB4S,EACpCC,EAAQlK,SACRkK,EAAQ9I,mBACR3J,EACAyS,EAAQ9F,wBAKVpG,EAD2B9G,EAAkBgT,EAAQ/S,aAAcC,EAAgBC,GACvDI,cAC7B,CAQD,GALA0S,EAAY7b,EAAc0P,GAG1B9O,EAAS,4BAA4ByI,EAAa,mBAAmBwS,EAAUf,cAAc,MAEzFe,GAAa3S,EACfE,GAAY,OACP,GAAIyS,EAAY,IAAK,CAC1B9a,EAAS,uCAAuC8a,KAChD,KACD,CAEDxS,GACD,CAED,MAAO,CACLF,iBACAC,YACAC,aACAP,iBACAC,iBAEJ,CC7EO,MAAMgT,EACX,WAAArW,Gd+BK,IAAiB5E,Ec9BpBqL,KAAK6P,aAAe,KACpB7P,KAAKiF,WAAa,GAClBjF,KAAK2G,mBAAqB,GAC1B3G,KAAKtD,aAAe,UACpBsD,KAAK8P,qBAAuB,Kd0BRnb,EcxBlB,yPdyBJJ,QAAQC,IAAI,YAAcG,EAAS,sCcvBjCF,EAAS,kCACV,CAOD,eAAAsb,CAAgBF,EAAchT,EAAU,IACtCmD,KAAK6P,aAAeA,EAGhBhT,GAASiT,uBACX9P,KAAK8P,qBAAuBjT,EAAQiT,qBACpCpb,EAAS,mCAGoB+D,IAA3BoE,GAASC,gBACXkD,KAAKlD,cAAgBD,EAAQC,oBAEJrE,IAAvBoE,GAASE,YACXiD,KAAKjD,UAAYF,EAAQE,WAG3BrI,EAAS,yBAAyBmb,IACnC,CAED,aAAAG,CAAc/K,GACZjF,KAAKiF,WAAaA,EAClBvQ,EAAS,oCAAoCuQ,EAAWnF,gBACzD,CAED,oBAAAmQ,CAAqBnJ,EAAaoJ,GAChClQ,KAAK2G,mBAAmBG,GAAeoJ,EACvCxb,EAAS,0CAA0CoS,YAAsBoJ,EAAU,KACpF,CAED,eAAAC,CAAgBzT,GACdsD,KAAKtD,aAAeA,EACpBhI,EAAS,yBAAyBgI,IACnC,CAOD,KAAA0T,CAAMvT,EAAU,IACTmD,KAAK6P,cAAiB7P,KAAKiF,YAAejF,KAAK2G,oBAClD/R,EAAS,mFAYX,IAAI+H,EAAiB,GACjBC,EAAiB,GACjBI,EAAiB,GACjB2S,EAAkB,GAGtBlb,EAAS,qBACT,MAAM8Q,EAAWP,EAAYhF,KAAKiF,YAClCxQ,EAAS,8BAGT,MAAMqa,EAAmB,CACvBzL,kBAAmBkC,EAASlC,kBAC5BW,kBAAmBuB,EAASvB,mBAO9B,GAHAvP,EAAS,gCACTF,QAAQ4I,KAAK,oBACb1I,EAAS,iBAAiBuL,KAAK6P,gBACL,yBAAtB7P,KAAK6P,aAEP,GAA0B,YAAtB7P,KAAKtD,aAA4B,CAMnCM,EALsBqN,EACpBjB,EACA7D,EACAvF,KAAK2G,oBAEwB3J,cACvC,KAAa,GAEFL,iBAAgBC,kBAAmB+L,EAA0BpD,EAAUvF,KAAK2G,qBAK/E3J,EAJ2BP,EAAkBuD,KAAKtD,aAAcC,EAAgBC,EAAgB,CAC9FE,cAAeD,EAAQC,eAAiBkD,KAAKlD,cAC7CC,UAAWF,EAAQE,WAAaiD,KAAKjD,YAEHC,cACrC,MACI,GAA0B,2BAAtBgD,KAAK6P,aAA2C,CAEzD,IAAIlG,EAAwB,EAC5B,MAAM0G,EAA2B,EAG3BZ,EAAU,CACdlK,SAAUA,EACVoB,mBAAoB3G,KAAK2G,mBACzBgD,sBAAuBA,EACvBjN,aAAcsD,KAAKtD,aACnBiT,kBAEA7S,cAAeD,EAAQC,eAAiBkD,KAAKlD,cAC7CC,UAAWF,EAAQE,WAAaiD,KAAKjD,WAGvC,KAAO4M,GAAyB,GAAG,CAEjC8F,EAAQ9F,sBAAwBA,EAG5B3M,EAAe/I,OAAS,IAC1Bwb,EAAQE,gBAAkB,IAAI3S,IAIhC,MAAMsT,EAAsBf,EAAc7F,EAA6B+F,GAGvE9S,EAAiB2T,EAAoB3T,eACrCC,EAAiB0T,EAAoB1T,eACrCI,EAAiBsT,EAAoBtT,eAGrC2M,GAAyB,EAAI0G,CAC9B,CACP,MAAW,GAA0B,yBAAtBrQ,KAAK6P,aAEd,GAA0B,YAAtB7P,KAAKtD,aACP9H,EACE,uGAEG,GAEF+H,iBAAgBC,kBC9JpB,SAAmC2I,EAAUoB,EAAoBmJ,GACtErb,EAAS,gDAGT,MAAM4O,kBACJA,EAAiBW,kBACjBA,EAAiBL,IACjBA,EAAGzB,iBACHA,EAAgBkD,cAChBA,EAAatF,cACbA,EAAaC,aACbA,GACEwF,GAGEzH,EAAEA,EAACyS,EAAEA,EAACC,EAAEA,EAACC,EAAEA,GAAMX,EAGjBlH,EAAUtD,EAAcC,IACxB3I,eACJA,EAAcD,eACdA,EAAcgJ,iBACdA,EAAgBF,eAChBA,EAAcX,YACdA,EAAWC,aACXA,EAAYa,SACZA,GACEgD,EAEJ,GAAsB,OAAlB9I,EAIF,IAAK,IAAI8D,EAAe,EAAGA,EAAewB,EAAexB,IAAgB,CAEvE,IAAK,IAAIqC,EAAiB,EAAGA,EAAiBL,EAAUK,IAEtDN,EAAiBM,GAAkB/R,KAAKuK,IAAIkF,EAAIC,GAAcqC,IAAmB,EAInF,IAAK,IAAImC,EAAkB,EAAGA,EAAkBtD,EAAY7Q,OAAQmU,IAAmB,CAErF,MAAMhI,cAAEA,EAAaC,sBAAEA,GAA0BoF,EAAexF,kBAC9D6E,EAAYsD,KAIRlC,YAAEA,EAAWC,oBAAEA,GAAwBN,EAA8B,CACzEzF,gBACAC,wBACAgD,oBACAsC,mBACAC,aAIF,IAAI8K,EAAS,EACb,IAAK,IAAI1c,EAAI,EAAGA,EAAI4R,EAAU5R,IAC5B0c,GAAUrN,EAAkBsC,EAAiB3R,IAAMoM,EAAcpM,GAInE,MAAM2c,EAAI7S,EAAE4S,GACN3S,EAAIwS,EAAEG,GACNlQ,EAAIgQ,EAAEE,GACNE,EAAIH,EAAEC,GAGZ,IAAK,IAAI3H,EAAkB,EAAGA,EAAkBnD,EAAUmD,IAAmB,CAC3E,MAAM8H,EAAmBlL,EAAiBoD,GAG1CnM,EAAeiU,IACb9L,EAAaqD,GAAmBlC,EAAc0K,EAAIxQ,EAAc2I,GAElE,IAAK,IAAIb,EAAkB,EAAGA,EAAkBtC,EAAUsC,IAAmB,CAC3E,MAAMC,EAAmBxC,EAAiBuC,GAG1CvL,EAAekU,GAAkB1I,IAC/BpD,EAAaqD,GACblC,EACAyK,EACAxK,EAAoB4C,GACpB5C,EAAoB+B,GAGtBvL,EAAekU,GAAkB1I,IAC/BpD,EAAaqD,GACblC,EACAnI,EACAoI,EAAoB+B,GACpB9H,EAAc2I,GAGhBpM,EAAekU,GAAkB1I,IAC/BpD,EAAaqD,GACblC,EACA1F,EACAJ,EAAc2I,GACd3I,EAAc8H,EACjB,CACF,CACF,CACF,KAC0B,OAAlBpI,GACTlL,EAAS,0EAkBX,OAbkC,IAAI2U,EACpC5C,EACAzE,EACAyB,EACA7D,EACAC,GAIwByJ,kCAAkC5M,EAAgBD,GAE5ElI,EAAS,8CAEF,CACLkI,iBACAC,iBAEJ,CD6B8CkU,CACpCvL,EACAvF,KAAK2G,mBACL3G,KAAK8P,uBAOP9S,EAJ2BP,EAAkBuD,KAAKtD,aAAcC,EAAgBC,EAAgB,CAC9FE,cAAeD,EAAQC,eAAiBkD,KAAKlD,cAC7CC,UAAWF,EAAQE,WAAaiD,KAAKjD,YAEHC,cACrC,CAKH,OAHAzI,QAAQoK,QAAQ,oBAChBlK,EAAS,6BAEF,CAAEuI,iBAAgB8R,mBAC1B,CAQD,gBAAMiC,CAAW9R,EAAepC,EAAU,IACnCmD,KAAK6P,cAAiB7P,KAAKiF,YAAejF,KAAK2G,oBAClD/R,EAAS,mFAGX,IAAI+H,EAAiB,GACjBC,EAAiB,GACjBI,EAAiB,GAErBvI,EAAS,qBACT,MAAM8Q,EAAWP,EAAYhF,KAAKiF,YAClCxQ,EAAS,8BACT,MAAMqa,EAAmB,CACvBzL,kBAAmBkC,EAASlC,kBAC5BW,kBAAmBuB,EAASvB,mBAO9B,GAJAvP,EAAS,gCACTF,QAAQ4I,KAAK,oBAEb1I,EAAS,iBAAiBuL,KAAK6P,gBACL,yBAAtB7P,KAAK6P,iBACJlT,iBAAgBC,kBAAmB+L,EAA0BpD,EAAUvF,KAAK2G,qBAErD,eAAtB3G,KAAKtD,cAA+B,CACtC,MAAQM,eAAgBkB,SAAYW,EAAuB,aAAclC,EAAgBC,EAAgB,CACvGqC,gBACAnC,cAAeD,EAAQC,eAAiBkD,KAAKlD,cAC7CC,UAAWF,EAAQE,WAAaiD,KAAKjD,YAEvCC,EAAiBkB,CAGlB,CAKH,OAHA3J,QAAQoK,QAAQ,oBAChBlK,EAAS,6BAEF,CAAEuI,iBAAgB8R,mBAC1B,EEpOE,MAACkC,EAAoBpS,MAAOqS,IAC/B,IAAIxR,EAAS,CACX4D,kBAAmB,GACnBW,kBAAmB,GACnB1C,eAAgB,CACdC,aAAc,GACdC,iBAAkB,IAEpBU,iBAAkB,GAClByE,mBAAoB,GACpBvE,kBAAmB,CAAE,EACrB8O,MAAO,EACPC,OAAO,EACPC,SAAU,IACV9N,YAAa,EACbW,YAAa,EACbhC,gBAAiB,GACjBN,aAAc,CAAE,GAId0P,SADgBJ,EAAKK,QAEtBC,MAAM,MACN5Z,KAAK6Z,GAASA,EAAKC,SACnBC,QAAQF,GAAkB,KAATA,GAAwB,MAATA,IAE/BG,EAAU,GACVC,EAAY,EAEZC,EAAmB,EACnBxM,EAAa,EACbyM,EAAsB,EACtBC,EAAmB,CAAEnM,SAAU,GAC/BoM,EAAoB,EACpBC,EAAW,GACXC,EAA2B,EAE3BC,EAAsB,EAEtBC,EAAyB,EACzBC,EAAsB,CACxBC,IAAK,EACL/P,IAAK,EACLgQ,YAAa,EACbhI,YAAa,GAEXiI,EAA2B,EAE3BC,EAAwB,CAAA,EAE5B,KAAOb,EAAYP,EAAMpd,QAAQ,CAC/B,MAAMud,EAAOH,EAAMO,GAEnB,GAAa,gBAATJ,EAAwB,CAC1BG,EAAU,aACVC,IACA,QACN,CAAW,GAAa,mBAATJ,EAA2B,CACpCG,EAAU,GACVC,IACA,QACN,CAAW,GAAa,mBAATJ,EAA2B,CACpCG,EAAU,gBACVC,IACA,QACN,CAAW,GAAa,sBAATJ,EAA8B,CACvCG,EAAU,GACVC,IACA,QACN,CAAW,GAAa,cAATJ,EAAsB,CAC/BG,EAAU,WACVC,IACA,QACN,CAAW,GAAa,iBAATJ,EAAyB,CAClCG,EAAU,GACVC,IACA,QACN,CAAW,GAAa,WAATJ,EAAmB,CAC5BG,EAAU,QACVC,IACA,QACN,CAAW,GAAa,cAATJ,EAAsB,CAC/BG,EAAU,GACVC,IACA,QACN,CAAW,GAAa,cAATJ,EAAsB,CAC/BG,EAAU,WACVC,IACA,QACN,CAAW,GAAa,iBAATJ,EAAyB,CAClCG,EAAU,GACVC,IACA,QACD,CAED,MAAMc,EAAQlB,EAAKD,MAAM,OAAOG,QAAQiB,GAAkB,KAATA,IAEjD,GAAgB,eAAZhB,EACFlS,EAAOyR,MAAQ0B,WAAWF,EAAM,IAChCjT,EAAO0R,MAAqB,MAAbuB,EAAM,GACrBjT,EAAO2R,SAAWsB,EAAM,QACnB,GAAgB,kBAAZf,GACT,GAAIe,EAAMze,QAAU,EAAG,CACrB,IAAK,QAAQmD,KAAKsb,EAAM,IAAK,CAC3Bd,IACA,QACD,CAED,MAAMtP,EAAYuQ,SAASH,EAAM,GAAI,IAC/BnQ,EAAMsQ,SAASH,EAAM,GAAI,IAC/B,IAAIpc,EAAOoc,EAAM3a,MAAM,GAAGyE,KAAK,KAC/BlG,EAAOA,EAAKwc,QAAQ,SAAU,IAE9BrT,EAAOwC,gBAAgBD,KAAK,CAC1BO,MACAD,YACAhM,QAEH,OACI,GAAgB,UAAZqb,EAAqB,CAC9B,GAAyB,IAArBE,EAAwB,CAC1BA,EAAmBgB,SAASH,EAAM,GAAI,IACtCrN,EAAawN,SAASH,EAAM,GAAI,IAChCjT,EAAO4D,kBAAoB,IAAIxH,MAAMwJ,GAAYlJ,KAAK,GACtDsD,EAAOuE,kBAAoB,IAAInI,MAAMwJ,GAAYlJ,KAAK,GACtDyV,IACA,QACD,CAED,GAAIE,EAAsBD,GAAkD,IAA9BE,EAAiBnM,SAAgB,CAC7EmM,EAAmB,CACjBO,IAAKO,SAASH,EAAM,GAAI,IACxBnQ,IAAKsQ,SAASH,EAAM,GAAI,IACxBK,WAAYF,SAASH,EAAM,GAAI,IAC/B9M,SAAUiN,SAASH,EAAM,GAAI,KAG/BT,EAAW,GACXD,EAAoB,EACpBE,EAA2B,EAE3BN,IACA,QACD,CAED,GAAII,EAAoBD,EAAiBnM,SAAU,CACjD,IAAK,IAAI5R,EAAI,EAAGA,EAAI0e,EAAMze,QAAU+d,EAAoBD,EAAiBnM,SAAU5R,IACjFie,EAASjQ,KAAK6Q,SAASH,EAAM1e,GAAI,KACjCge,IAGF,GAAIA,EAAoBD,EAAiBnM,SAAU,CACjDgM,IACA,QACD,CAEDA,IACA,QACD,CAED,GAAIM,EAA2BH,EAAiBnM,SAAU,CACxD,MAAMoN,EAAUf,EAASC,GAA4B,EAC/ChU,EAAI0U,WAAWF,EAAM,IACrBO,EAAIL,WAAWF,EAAM,IAE3BjT,EAAO4D,kBAAkB2P,GAAW9U,EACpCuB,EAAOuE,kBAAkBgP,GAAWC,EACpCxT,EAAO6D,cACP7D,EAAOwE,cAEPiO,IAEIA,IAA6BH,EAAiBnM,WAChDkM,IACAC,EAAmB,CAAEnM,SAAU,GAElC,CACP,MAAW,GAAgB,aAAZ+L,EAAwB,CACjC,GAA4B,IAAxBQ,EAA2B,CAC7BA,EAAsBU,SAASH,EAAM,GAAI,IACzBG,SAASH,EAAM,GAAI,IACnCd,IACA,QACD,CAED,GAAIQ,EAAyBD,GAA2D,IAApCE,EAAoB9H,YAAmB,CACzF8H,EAAsB,CACpBC,IAAKO,SAASH,EAAM,GAAI,IACxBnQ,IAAKsQ,SAASH,EAAM,GAAI,IACxBH,YAAaM,SAASH,EAAM,GAAI,IAChCnI,YAAasI,SAASH,EAAM,GAAI,KAGlCjT,EAAOkC,aAAa0Q,EAAoBE,cACrC9S,EAAOkC,aAAa0Q,EAAoBE,cAAgB,GAAKF,EAAoB9H,YAEpFiI,EAA2B,EAC3BZ,IACA,QACD,CAED,GAAIY,EAA2BH,EAAoB9H,YAAa,CAC3CsI,SAASH,EAAM,GAAI,IACtC,MAAMQ,EAAcR,EAAM3a,MAAM,GAAGJ,KAAKwb,GAAQN,SAASM,EAAK,MAE9D,GAAwC,IAApCd,EAAoBE,aAAyD,IAApCF,EAAoBE,YAAmB,CAClF,MAAMa,EAAcf,EAAoB9P,IAEnCkQ,EAAsBW,KACzBX,EAAsBW,GAAe,IAGvCX,EAAsBW,GAAapR,KAAKkR,GAGnCzT,EAAO2C,kBAAkBgR,KAC5B3T,EAAO2C,kBAAkBgR,GAAe,IAE1C3T,EAAO2C,kBAAkBgR,GAAapR,KAAKkR,EACrD,MAAuD,IAApCb,EAAoBE,YAE7B9S,EAAO6B,eAAeE,iBAAiBQ,KAAKkR,IACC,IAApCb,EAAoBE,aAGgB,KAApCF,EAAoBE,cAD7B9S,EAAO6B,eAAeC,aAAaS,KAAKkR,GAM1CV,IAEIA,IAA6BH,EAAoB9H,cACnD6H,IACAC,EAAsB,CAAE9H,YAAa,GAExC,CACF,CAEDqH,GACD,CAuBD,OApBAnS,EAAOwC,gBAAgBI,SAASpK,IAC9B,GAAuB,IAAnBA,EAAKqK,UAAiB,CACxB,MAAM+Q,EAAgBZ,EAAsBxa,EAAKsK,MAAQ,GAErD8Q,EAAcpf,OAAS,GACzBwL,EAAOkH,mBAAmB3E,KAAK,CAC7B1L,KAAM2B,EAAK3B,KACXiM,IAAKtK,EAAKsK,IACV+Q,MAAOD,GAGZ,KAGH3e,EACE,+CAA+C+M,KAAKC,UAClDjC,EAAO2C,2FAIJ3C,CAAM,ECtQR,SAAS8T,GACdvW,EACA8R,EACAe,EACA/P,EACA0T,EACAC,GAEA,MAAMpQ,kBAAEA,EAAiBW,kBAAEA,GAAsB8K,EAEjD,GAAsB,OAAlBhP,GAAuC,SAAb0T,EAAqB,CAEjD,IAAIE,EAEFA,EADE1W,EAAe/I,OAAS,GAAK4H,MAAMiD,QAAQ9B,EAAe,IACpDA,EAAerF,KAAKiE,GAAQA,EAAI,KAEhCoB,EAEEnB,MAAM8X,KAAKtQ,GAEvB,IAAIuQ,EAAW,CACb1V,EAAGmF,EACH4P,EAAGS,EACHG,KAAM,QACNrc,KAAM,UACNga,KAAM,CAAEsC,MAAO,mBAAoBC,MAAO,GAC1Czd,KAAM,YAGJ0d,EAAiB9f,KAAK+f,IAAIC,OAAOC,WAAY,KAI7CC,EAAS,CACXC,MAAO,eAAexE,IACtBkE,MALc7f,KAAK+f,IAAID,EAAgB,KAMvCM,OALe,IAMfC,MAAO,CAAEF,MAAO,KAChBG,MAAO,CAAEH,MAAO,YAChBI,OAAQ,CAAEC,EAAG,GAAI3Z,EAAG,GAAI4Z,EAAG,GAAI5W,EAAG,KAGpC6W,OAAOC,QAAQpB,EAAW,CAACG,GAAWQ,EAAQ,CAAEU,YAAY,GAC7D,MAAM,GAAsB,OAAlBhV,GAAuC,YAAb0T,EAAwB,CAE3D,IAAIuB,EAEFA,EADElZ,MAAMiD,QAAQ9B,EAAe,IACvBA,EAAerF,KAAKvC,GAAQA,EAAI,KAEhC4H,EAIV,IAAIgX,EAAiB9f,KAAK+f,IAAIC,OAAOC,WAAY,KAC7CnT,EAAO9M,KAAKsK,OAAO6E,GAEnB2R,EADO9gB,KAAKsK,OAAOwF,GACEhD,EACrBiU,EAAY/gB,KAAK+f,IAAID,EAAgB,KAIrCI,EAAS,CACXC,MAAO,GAAGb,YAAmB3D,IAC7BkE,MAAOkB,EACPX,OANeW,EAAYD,EAO3BT,MAAO,CAAEF,MAAO,KAChBG,MAAO,CAAEH,MAAO,KAChBI,OAAQ,CAAEC,EAAG,GAAI3Z,EAAG,GAAI4Z,EAAG,GAAI5W,EAAG,IAClCmX,UAAW,WAITC,EAAc,CAChBjX,EAAGmF,EACH4P,EAAGjP,EACHoR,EAAGL,EACHvd,KAAM,UACNga,KAAM,CACJ6D,UAAW,KAEbC,SAAU,CACRC,SAAU,UACVC,YAAY,GAGdC,SAAU,CACRpB,MAAO,YAET/d,KAAM,kBAGRse,OAAOC,QAAQpB,EAAW,CAAC0B,GAAcf,EAAQ,CAAEU,YAAY,GAChE,CACH,CC7FO,MAAMY,GAKX,WAAAnc,GACEyG,KAAKd,OAAS,KACdc,KAAK2V,UAAY,KACjB3V,KAAK4V,SAAU,EAEf5V,KAAK6V,aACN,CAOD,iBAAMA,GACJ,IACE7V,KAAKd,OAAS,IAAIC,OAAO,IAAIC,IAAI,iCAAkCC,KAAM,CACvE7H,KAAM,WAGRwI,KAAKd,OAAO4W,QAAWC,IACrBxhB,QAAQ6E,MAAM,iCAAkC2c,EAAM,EAExD,MAAMC,EAAgB1W,EAAaU,KAAKd,QAExCc,KAAK2V,gBAAkB,IAAIK,EAE3BhW,KAAK4V,SAAU,CAChB,CAAC,MAAOxc,GAEP,MADA7E,QAAQ6E,MAAM,8BAA+BA,GACvCA,CACP,CACF,CAQD,kBAAM6c,GACJ,OAAIjW,KAAK4V,QAAgBld,QAAQC,UAE1B,IAAID,SAAQ,CAACC,EAASud,KAC3B,IAAIC,EAAW,EACf,MAEMC,EAAa,KACjBD,IACInW,KAAK4V,QACPjd,IACSwd,GANO,GAOhBD,EAAO,IAAI9f,MAAM,2CAEjBigB,WAAWD,EAAY,IACxB,EAEHA,GAAY,GAEf,CAOD,qBAAMrG,CAAgBF,GAGpB,aAFM7P,KAAKiW,eACXxhB,EAAS,8CAA8Cob,KAChD7P,KAAK2V,UAAU5F,gBAAgBF,EACvC,CAOD,mBAAMG,CAAc/K,GAGlB,aAFMjF,KAAKiW,eACXxhB,EAAS,wCACFuL,KAAK2V,UAAU3F,cAAc/K,EACrC,CAQD,0BAAMgL,CAAqBnJ,EAAaoJ,GAGtC,aAFMlQ,KAAKiW,eACXxhB,EAAS,4DAA4DqS,KAC9D9G,KAAK2V,UAAU1F,qBAAqBnJ,EAAaoJ,EACzD,CAOD,qBAAMC,CAAgBzT,GAGpB,aAFMsD,KAAKiW,eACXxhB,EAAS,8CAA8CiI,KAChDsD,KAAK2V,UAAUxF,gBAAgBzT,EACvC,CAMD,WAAM0T,SACEpQ,KAAKiW,eACXxhB,EAAS,uDAET,MAAM6hB,EAAYC,YAAYC,MACxB/W,QAAeO,KAAK2V,UAAUvF,QAIpC,OADA3b,EAAS,4CAFO8hB,YAAYC,MAEmCF,GAAa,KAAMG,QAAQ,OACnFhX,CACR,CAMD,kBAAMiX,GAEJ,aADM1W,KAAKiW,eACJjW,KAAK2V,UAAUe,cACvB,CAMD,UAAMC,GAEJ,aADM3W,KAAKiW,eACJjW,KAAK2V,UAAUgB,MACvB,CAKD,SAAA/W,GACMI,KAAKd,SACPc,KAAKd,OAAOU,YACZI,KAAKd,OAAS,KACdc,KAAK2V,UAAY,KACjB3V,KAAK4V,SAAU,EAElB,EC9JS,MAACgB,GAAe"} \ No newline at end of file +{"version":3,"file":"feascript.esm.js","sources":["../src/methods/euclideanNormScript.js","../src/utilities/loggingScript.js","../src/vendor/comlink.mjs","../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/models/thermalBoundaryConditionsScript.js","../src/models/heatConductionScript.js","../src/models/genericBoundaryConditionsScript.js","../src/models/frontPropagationScript.js","../src/methods/frontalSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/FEAScript.js","../src/models/generalFormPDEScript.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.js","../src/workers/workerScript.js","../src/index.js"],"sourcesContent":["/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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;\");\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;\");\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;\");\n}\n\n/**\n * Function to log warning messages\n * @param {string} message - Message to log\n */\nexport function warnLog(message) {\n console.log(\"%c[WARN] \" + message, \"color: #FF9800; font-weight: bold;\");\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 * @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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { jacobiSolver } from \"./jacobiSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\nimport * as Comlink from \"../vendor/comlink.mjs\";\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] - Optional parameters for the solver, such as `maxIterations` and `tolerance`\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\n // Extract options\n const { maxIterations = 10000, tolerance = 1e-4 } = 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// Helper to lazily create a default WebGPU compute engine (Comlink + worker)\nasync function createDefaultComputeEngine() {\n const worker = new Worker(new URL(\"../workers/webgpuWorkerScript.js\", import.meta.url), {\n type: \"module\",\n });\n const computeEngine = Comlink.wrap(worker);\n await computeEngine.initialize();\n return { computeEngine, worker };\n}\n\n/**\n * Function to solve asynchronously a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (e.g., \"jacobi-gpu\")\n * @param {array} jacobianMatrix - The coefficient matrix\n * @param {array} residualVector - The right-hand side vector\n * @param {object} [options] - Optional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {Promise} A promise that resolves to 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 async function solveLinearSystemAsync(solverMethod, jacobianMatrix, residualVector, options = {}) {\n \n // Extract options\n const { maxIterations = 10000, tolerance = 1e-4 } = options;\n\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n // Normalize inputs\n const A = Array.isArray(jacobianMatrix) ? jacobianMatrix : jacobianMatrix?.toArray?.() ?? jacobianMatrix;\n const b = Array.isArray(residualVector) ? residualVector : residualVector?.toArray?.() ?? residualVector;\n\n let created = null;\n let computeEngine = null;\n\n let solutionVector = [];\n let converged = true;\n let iterations;\n\n if (solverMethod === \"jacobi-gpu\") {\n // Spin up a worker-backed compute engine\n created = await createDefaultComputeEngine();\n computeEngine = created.computeEngine;\n\n const x0 = new Array(b.length).fill(0);\n let result;\n\n result = await computeEngine.webgpuJacobiSolver(A, b, x0, { maxIterations, tolerance });\n solutionVector = result.solutionVector;\n converged = result.converged;\n iterations = result.iterations;\n\n // Log convergence information\n if (converged) {\n debugLog(`Jacobi method converged in ${iterations} iterations`);\n } else {\n errorLog(`Jacobi method did not converge after ${iterations} iterations`);\n }\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(`System solved successfully (${solverMethod})`);\n\n if (created) {\n await computeEngine?.destroy?.().catch(() => { });\n created.worker.terminate();\n }\n\n return { solutionVector, converged, iterations };\n}\n","/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method (CPU synchronous version)\n * @param {array} A - The system matrix\n * @param {array} b - The right-hand side vector\n * @param {array} x0 - Initial guess for solution vector\n * @param {object} [options] - Optional parameters for the solver, such as `maxIterations` and `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(A, b, x0, options = {}) {\n // Extract options\n const { maxIterations, tolerance } = options;\n\n const n = A.length;\n let x = [...x0];\n let xNew = new Array(n);\n\n // Jacobi update: xNew[i] = (b[i] - sum(A[i][j] * x[j] for j != i)) / A[i][i]\n for (let iter = 0; iter < maxIterations; iter++) {\n for (let i = 0; i < n; i++) {\n let sum = 0;\n for (let j = 0; j < n; j++) {\n if (i !== j) {\n sum += A[i][j] * x[j];\n }\n }\n xNew[i] = (b[i] - sum) / A[i][i];\n }\n\n // Check convergence based on maximum difference in solution vector\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 // Copy new solution for the next iteration\n x = [...xNew];\n\n if (maxDiff < tolerance) {\n return { solutionVector: x, iterations: iter + 1, converged: true };\n }\n }\n\n return { solutionVector: x, iterations: maxIterations, converged: false };\n}\n","/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 this parsed mesh was already converted in a previous run, don't re-process it.\n // Just mark this Mesh instance as ready so prepareMesh() doesn't fall back to generateMesh().\n if (Array.isArray(this.parsedMesh.nodalNumbering)) {\n this.boundaryElementsProcessed = true;\n this.parsedMesh.boundaryElementsProcessed = true;\n return this.parsedMesh;\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 elementIndex = 0; elementIndex < quadElements.length; elementIndex++) {\n const gmshNodes = quadElements[elementIndex];\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 (\n let elementIndex = 0;\n elementIndex < this.parsedMesh.nodalNumbering.length;\n elementIndex++\n ) {\n const elementConnectivity = this.parsedMesh.nodalNumbering[elementIndex];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elementConnectivity.length === 4) {\n // Check if both boundary nodes are in this element\n if (elementConnectivity.includes(node1) && elementConnectivity.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elementConnectivity.indexOf(node1);\n const node2Index = elementConnectivity.indexOf(node2);\n\n debugLog(\n ` Found element ${elementIndex} containing boundary nodes. Element nodes: [${elementConnectivity.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 ${elementIndex}`);\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 ${elementIndex}`);\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 ${elementIndex}`);\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 ${elementIndex}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elementIndex, side]);\n debugLog(\n ` Added element-side pair [${elementIndex}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elementConnectivity.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elementConnectivity.includes(node1) && elementConnectivity.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elementConnectivity.indexOf(node1);\n const node2Index = elementConnectivity.indexOf(node2);\n\n debugLog(\n ` Found element ${elementIndex} containing boundary nodes. Element nodes: [${elementConnectivity.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 ${elementIndex}`);\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 ${elementIndex}`);\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 ${elementIndex}`);\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 ${elementIndex}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elementIndex, side]);\n debugLog(\n ` Added element-side pair [${elementIndex}, ${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.generateNodalNumbering1D(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 generateNodalNumbering1D(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 an 1D 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 * 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; // Two sides for 1D case (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.generateNodalNumbering2D(\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 generateNodalNumbering2D(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 2D 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 * 0 - Bottom side of reference element (maps to physical bottom boundary in the case of a rectangular domain)\n * 1 - Left side of reference element (maps to physical left boundary in the case of a rectangular domain)\n * 2 - Top side of reference element (maps to physical top boundary in the case of a rectangular domain)\n * 3 - Right side of reference element (maps to physical right boundary in the case of a rectangular domain)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // Four sides for a rectangle 2D case (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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n// Internal imports\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 (e.g., from a Gmsh .msh import) if provided. Otherwise, generate a structured mesh\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 nodesPerElement = nop[0].length;\n\n return {\n residualVector,\n jacobianMatrix,\n localToGlobalMap,\n basisFunctions,\n gaussPoints,\n gaussWeights,\n nodesPerElement,\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, nodesPerElement } =\n params;\n\n let xCoordinates = 0;\n let ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; 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 < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; 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 < nodesPerElement; 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 * Function to test if a point is inside a triangle using barycentric coordinates,\n * also returning the natural coordinates (ksi, eta).\n * @param {number} x - X-coordinate of the point\n * @param {number} y - Y-coordinate of the point\n * @param {array} vertices - Triangle vertices [[x0,y0],[x1,y1],[x2,y2]]\n * @returns {object} Object containing inside boolean and natural coordinates {inside, ksi, eta}\n */\nexport function pointInsideTriangle(x, y, vertices) {\n const tolerance = 1e-12;\n const [v0, v1, v2] = vertices;\n\n const denom = (v1[1] - v2[1]) * (v0[0] - v2[0]) + (v2[0] - v1[0]) * (v0[1] - v2[1]);\n\n const ksi = ((v1[1] - v2[1]) * (x - v2[0]) + (v2[0] - v1[0]) * (y - v2[1])) / denom;\n const eta = ((v2[1] - v0[1]) * (x - v2[0]) + (v0[0] - v2[0]) * (y - v2[1])) / denom;\n const gamma = 1 - ksi - eta;\n\n const inside = ksi >= -tolerance && eta >= -tolerance && gamma >= -tolerance;\n return { inside, ksi, eta };\n}\n\n/**\n * Function to test if a point is inside a quadrilateral by spliting it into triangles and using barycentric coordinates\n * @param {number} x - X-coordinate of the point\n * @param {number} y - Y-coordinate of the point\n * @param {array} vertices - Quadrilateral vertices [[x0,y0],[x1,y1],[x2,y2],[x3,y3]]\n * @returns {object} Object containing inside boolean and natural coordinates {inside, ksi, eta}\n */\nexport function pointInsideQuadrilateral(x, y, vertices) {\n const [firstTriangleVertices, secondTriangleVertices] = splitQuadrilateral(vertices);\n const pointInsideFirstTriangle = pointInsideTriangle(x, y, firstTriangleVertices);\n const pointInsideSecondTriangle = pointInsideTriangle(x, y, secondTriangleVertices);\n\n const inside = pointInsideFirstTriangle.inside || pointInsideSecondTriangle.inside;\n let ksi = 0;\n let eta = 0;\n\n if (inside) {\n const [v0, v1, v2, v3] = vertices;\n\n // Function to calculate distance from point to line segment\n const getDistanceFromLine = (p1, p2) => {\n const num = Math.abs((p2[0] - p1[0]) * (p1[1] - y) - (p1[0] - x) * (p2[1] - p1[1]));\n const den = Math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2);\n return num / den;\n };\n\n // Calculate distances to edges based on vertex order:\n // 1 (v1) --- 3 (v3)\n // | |\n // 0 (v0) --- 2 (v2)\n\n const distLeft = getDistanceFromLine(v0, v1);\n const distRight = getDistanceFromLine(v2, v3);\n const distBottom = getDistanceFromLine(v0, v2);\n const distTop = getDistanceFromLine(v1, v3);\n\n ksi = distLeft / (distLeft + distRight);\n eta = distBottom / (distBottom + distTop);\n }\n\n return { inside, ksi, eta };\n}\n\n/**\n * Function to split the quadrilateral elements into two triangles\n * @param {array} vertices - Quadrilateral vertices [[x0,y0],[x1,y1],[x2,y2],[x3,y3]]\n * @returns {array} Array of triangle vertices: [[v0,v1,v3], [v0,v2,v3]]\n */\nexport function splitQuadrilateral(vertices) {\n const [v0, v1, v2, v3] = vertices;\n // Vertices order:\n // 1 --- 3\n // | |\n // 0 --- 2\n return [\n [v0, v1, v3],\n [v0, v2, v3],\n ];\n}\n\n/**\n * Function that finds the list of adjacent elements for each node in the mesh\n * @param {object} meshData - Object containing nodal numbering (NOP)\n * @returns {object} Object containing:\n * - nodeNeighbors: Indices of neighboring elements per node\n * - neighborCount: Total number of neighboring elements per node\n */\nexport function computeNodeNeighbors(meshData) {\n const { nop, nodesXCoordinates } = meshData;\n const totalNodes = nodesXCoordinates.length;\n const nodesPerElement = nop[0].length;\n\n // Initialize arrays\n const nodeNeighbors = Array.from({ length: totalNodes }, () => []);\n const neighborCount = Array(totalNodes).fill(0);\n\n // Loop through all elements\n for (let elemIndex = 0; elemIndex < nop.length; elemIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) {\n const nodeIndex = nop[elemIndex][localNodeIndex] - 1;\n\n // Increment the total number of neighboring elements for this node\n neighborCount[nodeIndex] = neighborCount[nodeIndex] + 1;\n\n // Store the element index as a neighbor of this node\n nodeNeighbors[nodeIndex].push(elemIndex);\n }\n }\n\n return { nodeNeighbors, neighborCount };\n}\n\n/**\n * Function to extracts boundary line segments for ray casting\n * @param {object} meshData - Object containing mesh data\n * @returns {array} Array of segments\n */\nexport function getBoundarySegments(meshData) {\n let boundaryLineElements = [];\n let boundaryNodesSegments = [];\n let boundaryGlobalElementIndex = 0;\n let boundarySides;\n const { nodesXCoordinates, nodesYCoordinates, nop, boundaryElements, meshDimension, elementOrder } =\n meshData;\n\n if (meshDimension === \"1D\") {\n if (elementOrder === \"linear\") {\n 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 } else if (elementOrder === \"quadratic\") {\n 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 } else if (meshDimension === \"2D\") {\n if (elementOrder === \"linear\") {\n 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 } else if (elementOrder === \"quadratic\") {\n 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 }\n\n // Iterate over all boundaries\n for (let boundaryIndex = 0; boundaryIndex < boundaryElements.length; boundaryIndex++) {\n // Iterate over all elements in the current boundary\n for (\n let boundaryLocalElementIndex = 0;\n boundaryLocalElementIndex < boundaryElements[boundaryIndex].length;\n boundaryLocalElementIndex++\n ) {\n boundaryLineElements[boundaryGlobalElementIndex] =\n boundaryElements[boundaryIndex][boundaryLocalElementIndex];\n boundaryGlobalElementIndex++;\n // Retrieve the element index and the side\n const [elementIndex, side] = boundaryElements[boundaryIndex][boundaryLocalElementIndex];\n let boundaryLocalNodeIndices = boundarySides[side];\n let currentElementNodesX = [];\n let currentElementNodesY = [];\n\n for (\n let boundaryLocalNodeIndex = 0;\n boundaryLocalNodeIndex < boundaryLocalNodeIndices.length;\n boundaryLocalNodeIndex++\n ) {\n const globalNodeIndex = nop[elementIndex][boundaryLocalNodeIndices[boundaryLocalNodeIndex]] - 1;\n\n currentElementNodesX.push(nodesXCoordinates[globalNodeIndex]);\n currentElementNodesY.push(nodesYCoordinates[globalNodeIndex]);\n }\n\n // Create segments for this element\n for (let k = 0; k < currentElementNodesX.length - 1; k++) {\n boundaryNodesSegments.push([\n [currentElementNodesX[k], currentElementNodesY[k]],\n [currentElementNodesX[k + 1], currentElementNodesY[k + 1]],\n ]);\n }\n }\n }\n return boundaryNodesSegments;\n}\n","/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 1: [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 nodesPerElement = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < nodesPerElement; 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 nodesPerElement = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < nodesPerElement; 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 nodesPerElement = this.nop[elementIndex].length;\n const localJacobianMatrix = Array(nodesPerElement)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n const localResidualVector = Array(nodesPerElement).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 ([boundaryElementIndex, _]) => boundaryElementIndex === 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 < nodesPerElement; 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 nodesPerElement = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < nodesPerElement; 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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 nodesPerElement,\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 < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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, nodesPerElement } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(nodesPerElement)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n const localResidualVector = Array(nodesPerElement).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(nodesPerElement);\n const localToGlobalMap = Array(nodesPerElement);\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; 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 nodesPerElement,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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 nodesPerElement,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 1: [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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 nodesPerElement,\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 < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; 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 < nodesPerElement; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; 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 < nodesPerElement; 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 < nodesPerElement; 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, nodesPerElement } = 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(nodesPerElement)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n const localResidualVector = Array(nodesPerElement).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(nodesPerElement);\n const localToGlobalMap = Array(nodesPerElement);\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; 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 < nodesPerElement; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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 nodesPerElement,\n });\n\n // Calculate solution derivatives\n let solutionDerivX = 0;\n let solutionDerivY = 0;\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; 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 < nodesPerElement; 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 < nodesPerElement; 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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { initializeFEA } from \"../mesh/meshUtilsScript.js\";\nimport { assembleHeatConductionFront } from \"../models/heatConductionScript.js\";\nimport { ThermalBoundaryConditions } from \"../models/thermalBoundaryConditionsScript.js\";\nimport { assembleFrontPropagationFront } from \"../models/frontPropagationScript.js\";\nimport { GenericBoundaryConditions } from \"../models/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 nodesPerElement = FEAData.nodesPerElement;\n\n // Calculate required array sizes\n initializeFrontalArrays(nodesPerElement, 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.nodesPerElement; 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.nodesPerElement;\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} nodesPerElement - Number of nodes per element\n * @param {number} numElements - Number of elements in the mesh\n */\nfunction initializeFrontalArrays(nodesPerElement, numElements) {\n // Use the actual number of elements from the mesh\n frontalData.nodalNumbering = Array(numElements)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n frontalData.nodeConstraintCode = Array(nodesPerElement).fill(0);\n frontalData.boundaryValues = Array(nodesPerElement).fill(0);\n frontalData.globalResidualVector = Array(nodesPerElement).fill(0);\n frontalData.solutionVector = Array(nodesPerElement).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 = nodesPerElement;\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(nodesPerElement, 2000);\n frontalState.globalSolutionVector = Array(systemSize).fill(0);\n frontalState.frontDataIndex = 0;\n\n // Initialize elementData arrays\n elementData.localJacobianMatrix = Array(nodesPerElement)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n elementData.currentElementIndex = 0;\n\n // Initialize frontStorage arrays\n const frontSize = estimateFrontSize(nodesPerElement, 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} nodesPerElement - 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(nodesPerElement, numElements) {\n const frontWidthEstimate = Math.max(Math.ceil(Math.sqrt(numElements)) * nodesPerElement, nodesPerElement * 2);\n return frontWidthEstimate * numElements;\n}\n// Old function to estimate the required front size\n// function estimateFrontSize(nodesPerElement, numElements, nodesPerElement) {\n// const frontWidthEstimate = Math.ceil(Math.sqrt(numElements) * nodesPerElement * 2);\n// const frontSize = frontWidthEstimate * nodesPerElement * 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.nodesPerElement)\n .fill()\n .map(() => Array(FEAData.nodesPerElement).fill(0));\n let boundaryResidualVector = Array(FEAData.nodesPerElement).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(([boundaryElementIndex, _]) => boundaryElementIndex === 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.nodesPerElement; localNodeI++) {\n for (let localNodeJ = 0; localNodeJ < FEAData.nodesPerElement; 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.nodesPerElement; 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 nodesPerElement = meshData.nodesXCoordinates.length;\n const systemSize = Math.max(nodesPerElement, frontalState.globalSolutionVector.length);\n let localDestination = Array(FEAData.nodesPerElement).fill(0);\n let rowDestination = Array(FEAData.nodesPerElement).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(nodesPerElement).fill(0);\n let columnSwapCount = Array(nodesPerElement).fill(0);\n let lastAppearanceCheck = Array(nodesPerElement).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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 \"../models/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 * @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 = {}) {\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 // Extract context\n const { maxIterations = 100, tolerance = 1e-4 } = context;\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { solveLinearSystemAsync } from \"./methods/linearSystemSolverScript.js\";\nimport { prepareMesh } from \"./mesh/meshUtilsScript.js\";\nimport { assembleFrontPropagationMat } from \"./models/frontPropagationScript.js\";\nimport { assembleGeneralFormPDEMat, assembleGeneralFormPDEFront } from \"./models/generalFormPDEScript.js\";\nimport { assembleHeatConductionMat, assembleHeatConductionFront } from \"./models/heatConductionScript.js\";\nimport { runFrontalSolver } from \"./methods/frontalSolverScript.js\";\nimport { basicLog, debugLog, warnLog, 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 containifng the solution vector and 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 warnLog(\n \"FEAScript is provided “as is” without any warranty. The authors are not responsible for any damages or losses that may result from using the software. See the license for more details: https://github.com/FEAScript/FEAScript-core/blob/main/LICENSE\"\n );\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?.coefficientFunctions) {\n this.coefficientFunctions = options.coefficientFunctions;\n debugLog(\"Coefficient functions set\");\n }\n // Only update if a value is provided, otherwise keep the default\n if (options?.maxIterations !== undefined) {\n this.maxIterations = options.maxIterations;\n }\n if (options?.tolerance !== undefined) {\n this.tolerance = options.tolerance;\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 /**\n * Function to solve the finite element problem synchronously\n * @param {object} [options] - Additional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {object} An object containing the solution vector and mesh information\n */\n solve(options = {}) {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n errorLog(\"Solver config, mesh config, and boundary conditions must be set before solving.\");\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 and nodal numbering 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 basicLog(`Using solver: ${this.solverConfig}`);\n if (this.solverConfig === \"heatConductionScript\") {\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 maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n });\n solutionVector = linearSystemResult.solutionVector;\n }\n } else if (this.solverConfig === \"frontPropagationScript\") {\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 // TODO: Consider using different maxIterations/tolerance for Newton-Raphson and linear solver\n maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\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);\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 // 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 maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n });\n solutionVector = linearSystemResult.solutionVector;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n\n /**\n * Function to solve the finite element problem asynchronously\n * @param {object} computeEngine - The compute engine to use for the asynchronous solver (e.g., a worker or a WebGPU context)\n * @param {object} [options] - Additional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {Promise} A promise that resolves to an object containing the solution vector and the coordinates of the mesh nodes\n */\n async solveAsync(computeEngine, options = {}) {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n errorLog(\"Solver config, mesh config, and boundary conditions must be set before solving.\");\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n\n basicLog(\"Preparing mesh...\");\n const meshData = prepareMesh(this.meshConfig);\n basicLog(\"Mesh preparation completed\");\n const nodesCoordinates = {\n nodesXCoordinates: meshData.nodesXCoordinates,\n nodesYCoordinates: meshData.nodesYCoordinates,\n };\n\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n\n basicLog(`Using solver: ${this.solverConfig}`);\n if (this.solverConfig === \"heatConductionScript\") {\n ({ jacobianMatrix, residualVector } = assembleHeatConductionMat(meshData, this.boundaryConditions));\n\n if (this.solverMethod === \"jacobi-gpu\") {\n const { solutionVector: x } = await solveLinearSystemAsync(\n \"jacobi-gpu\",\n jacobianMatrix,\n residualVector,\n {\n computeEngine,\n maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n }\n );\n solutionVector = x;\n } else {\n // Other async solver\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 nodesPerElement,\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 < nodesPerElement; 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 nodesPerElement,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < nodesPerElement; 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 < nodesPerElement; 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 < nodesPerElement; 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, nodesPerElement } = 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(nodesPerElement)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n const localResidualVector = Array(nodesPerElement).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(nodesPerElement);\n const localToGlobalMap = Array(nodesPerElement);\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; 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 nodesPerElement,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < nodesPerElement; 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 < nodesPerElement; 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 < nodesPerElement; 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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport {\n prepareMesh,\n pointInsideTriangle,\n pointInsideQuadrilateral,\n computeNodeNeighbors,\n getBoundarySegments,\n} from \"../mesh/meshUtilsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { initializeFEA } from \"../mesh/meshUtilsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to create plots of the solution vector\n * @param {object} result - Object containing solution vector and mesh information\n * @param {object} model - Object containing model properties\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n */\nexport function plotSolution(model, result, plotType, plotDivId) {\n const { nodesXCoordinates, nodesYCoordinates } = result.nodesCoordinates;\n const solutionVector = result.solutionVector;\n const solverConfig = model.solverConfig;\n const meshDimension = model.meshConfig.meshDimension;\n const meshData = prepareMesh(model.meshConfig); // Retrieve mesh connectivity details (used in splitQuadrilateral)\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: nodesXCoordinates,\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 plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = 300;\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: 50, r: 50, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Check if solutionVector is a nested array\n let zData;\n if (Array.isArray(solutionVector[0])) {\n zData = solutionVector.map((val) => val[0]);\n } else {\n zData = solutionVector;\n }\n\n // Plot sizing parameters\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;\n\n // 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 // Create the plot\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zData,\n type: \"contour\",\n line: {\n smoothing: 0.85,\n },\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 Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n}\n\n/**\n * Function to generate a dense visualization grid and interpolate the FEM solution on it\n * @param {object} result - Object containing solution vector and mesh information\n * @param {object} model - Object containing model properties\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n */\nexport function plotInterpolatedSolution(model, result, plotType, plotDivId) {\n const { nodesXCoordinates, nodesYCoordinates } = result.nodesCoordinates; // TODO: Check if we should place it inside the 2D block\n const meshDimension = model.meshConfig.meshDimension;\n const meshData = prepareMesh(model.meshConfig); // Retrieve mesh connectivity details\n\n // Initialize BasisFunctions once here to avoid creating it inside the loop\n const basisFunctions = new BasisFunctions({\n meshDimension: model.meshConfig.meshDimension,\n elementOrder: model.meshConfig.elementOrder,\n });\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // 1D plot region\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n const visNodeXCoordinates = [];\n const visNodeYCoordinates = [];\n let visSolution = [];\n const visNodesX = 1e2; // Number of nodes along the x-axis of the visualization grid\n const visNodesY = 1e2; // Number of nodes along the y-axis of the visualization grid\n\n // const { nodesXCoordinates, nodesYCoordinates } = result.nodesCoordinates;\n const deltavisX = (Math.max(...nodesXCoordinates) - Math.min(...nodesXCoordinates)) / (visNodesX - 1);\n const deltavisY = (Math.max(...nodesYCoordinates) - Math.min(...nodesYCoordinates)) / (visNodesY - 1);\n\n visNodeXCoordinates[0] = Math.min(...nodesXCoordinates);\n visNodeYCoordinates[0] = Math.min(...nodesYCoordinates);\n\n for (let visNodeIndexY = 1; visNodeIndexY < visNodesY; visNodeIndexY++) {\n visNodeXCoordinates[visNodeIndexY] = visNodeXCoordinates[0];\n visNodeYCoordinates[visNodeIndexY] = visNodeYCoordinates[0] + visNodeIndexY * deltavisY;\n }\n\n for (let visNodeIndexX = 1; visNodeIndexX < visNodesX; visNodeIndexX++) {\n const nnode = visNodeIndexX * visNodesY;\n visNodeXCoordinates[nnode] = visNodeXCoordinates[0] + visNodeIndexX * deltavisX;\n visNodeYCoordinates[nnode] = visNodeYCoordinates[0];\n\n for (let visNodeIndexY = 1; visNodeIndexY < visNodesY; visNodeIndexY++) {\n visNodeXCoordinates[nnode + visNodeIndexY] = visNodeXCoordinates[nnode];\n visNodeYCoordinates[nnode + visNodeIndexY] = visNodeYCoordinates[nnode] + visNodeIndexY * deltavisY;\n }\n }\n\n const visNodeCoordinates = { visNodeXCoordinates, visNodeYCoordinates };\n\n // Initialize visSolution with null for all visualization nodes\n visSolution = new Array(visNodesX * visNodesY).fill(null);\n\n // Get boundary segments for ray casting\n const boundarySegments = getBoundarySegments(meshData);\n\n // Perform adjacency-based search to find which element contains a given point (quick search)\n const { nodeNeighbors, neighborCount } = computeNodeNeighbors(meshData);\n let lastParentElement = 0;\n for (let visNodeIndex = 0; visNodeIndex < visNodesX * visNodesY; visNodeIndex++) {\n // Ray casting check\n if (\n !pointInsidePolygon(\n visNodeXCoordinates[visNodeIndex],\n visNodeYCoordinates[visNodeIndex],\n boundarySegments\n )\n ) {\n continue;\n }\n let found = false;\n for (\n let localNodeIndex = 0;\n localNodeIndex < meshData.nop[lastParentElement].length;\n localNodeIndex++\n ) {\n let globalNodeIndex = meshData.nop[lastParentElement][localNodeIndex] - 1;\n for (\n let neighborElementsIndex = 0;\n neighborElementsIndex < neighborCount[globalNodeIndex];\n neighborElementsIndex++\n ) {\n let currentElement = nodeNeighbors[globalNodeIndex][neighborElementsIndex];\n const searchResult = pointSearch(\n model,\n meshData,\n result,\n currentElement,\n visNodeXCoordinates[visNodeIndex],\n visNodeYCoordinates[visNodeIndex],\n basisFunctions\n );\n\n if (searchResult.inside) {\n lastParentElement = currentElement;\n visSolution[visNodeIndex] = searchResult.value;\n found = true;\n break;\n }\n }\n if (found) break;\n }\n\n // Scan all elements to find which element contains a given point (slow search)\n if (!found) {\n for (let currentElement = 0; currentElement < meshData.nop.length; currentElement++) {\n const searchResult = pointSearch(\n model,\n meshData,\n result,\n currentElement,\n visNodeXCoordinates[visNodeIndex],\n visNodeYCoordinates[visNodeIndex],\n basisFunctions\n );\n\n if (searchResult.inside) {\n lastParentElement = currentElement;\n visSolution[visNodeIndex] = searchResult.value;\n found = true;\n break;\n }\n }\n }\n }\n\n // Plot sizing parameters\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;\n\n // Layout properties\n let layout = {\n title: `${plotType} plot (interpolated) - ${model.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 // Create the plot\n let contourData = {\n x: visNodeXCoordinates,\n y: visNodeYCoordinates,\n z: visSolution,\n type: \"contour\",\n line: {\n smoothing: 0.85,\n },\n contours: {\n coloring: \"heatmap\",\n showlabels: false,\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: \"Solution\",\n },\n name: \"Interpolated Solution Field\",\n };\n\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n}\n\n/**\n * Function to search if a point is inside an element and interpolate the solution\n * @param {object} model - Object containing model properties\n * @param {object} meshData - Object containing mesh data\n * @param {object} result - Object containing solution vector and mesh information\n * @param {number} currentElement - Index of the element to check\n * @param {number} visNodeXCoordinate - X-coordinate of the point\n * @param {number} visNodeYCoordinate - Y-coordinate of the point\n * @param {object} basisFunctions - Instance of BasisFunctions class\n * @returns {object} Object containing inside boolean and interpolated value\n */\nfunction pointSearch(model, meshData, result, currentElement, visNodeXCoordinate, visNodeYCoordinate, basisFunctions) {\n const { nodesXCoordinates, nodesYCoordinates } = result.nodesCoordinates;\n const nodesPerElement = meshData.nop[currentElement].length;\n\n if (nodesPerElement === 4) {\n // Linear quadrilateral element\n let vertices = [\n [\n nodesXCoordinates[meshData.nop[currentElement][0] - 1],\n nodesYCoordinates[meshData.nop[currentElement][0] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][1] - 1],\n nodesYCoordinates[meshData.nop[currentElement][1] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][2] - 1],\n nodesYCoordinates[meshData.nop[currentElement][2] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][3] - 1],\n nodesYCoordinates[meshData.nop[currentElement][3] - 1],\n ],\n ];\n const pointCheck = pointInsideQuadrilateral(visNodeXCoordinate, visNodeYCoordinate, vertices);\n if (pointCheck.inside) {\n return {\n inside: true,\n value: solutionInterpolation(model, meshData, result, currentElement, pointCheck.ksi, pointCheck.eta, basisFunctions),\n };\n }\n } else if (nodesPerElement === 9) {\n // Quadratic quadrilateral element\n let vertices = [\n [\n nodesXCoordinates[meshData.nop[currentElement][0] - 1],\n nodesYCoordinates[meshData.nop[currentElement][0] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][2] - 1],\n nodesYCoordinates[meshData.nop[currentElement][2] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][6] - 1],\n nodesYCoordinates[meshData.nop[currentElement][6] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][8] - 1],\n nodesYCoordinates[meshData.nop[currentElement][8] - 1],\n ],\n ];\n const pointCheck = pointInsideQuadrilateral(visNodeXCoordinate, visNodeYCoordinate, vertices);\n if (pointCheck.inside) {\n return {\n inside: true,\n value: solutionInterpolation(model, meshData, result, currentElement, pointCheck.ksi, pointCheck.eta, basisFunctions),\n };\n }\n } // TODO: Add also triangular element cases\n return { inside: false, value: null };\n}\n\n/**\n * Function to interpolate the solution at a specific point (ksi, eta) within an element\n * @param {object} model - Object containing model properties\n * @param {object} meshData - Object containing mesh data\n * @param {object} result - Object containing solution vector and mesh information\n * @param {number} elementIndex - Index of the element containing the point\n * @param {number} ksi - First natural coordinate (ksi)\n * @param {number} eta - Second natural coordinate (eta)\n * @param {object} basisFunctions - Instance of BasisFunctions class\n * @returns {number} Interpolated solution value\n */\nfunction solutionInterpolation(model, meshData, result, elementIndex, ksi, eta, basisFunctions) {\n // Initialize FEA components\n const solutionVector = result.solutionVector;\n const nodesPerElement = meshData.nop[elementIndex].length;\n\n // Get basis functions for the current point\n const basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(ksi, eta);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n\n // Check if solutionVector is a nested array\n let zData;\n if (Array.isArray(solutionVector[0])) {\n zData = solutionVector.map((val) => val[0]);\n } else {\n zData = solutionVector;\n }\n\n // Interpolate solution\n let solutionInterpolationValue = 0;\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) {\n solutionInterpolationValue +=\n zData[meshData.nop[elementIndex][localNodeIndex] - 1] * basisFunction[localNodeIndex];\n }\n\n return solutionInterpolationValue;\n}\n\n/**\n * Function to check if a point is inside a polygon using ray casting algorithm\n * @param {number} x - X-coordinate of the point\n * @param {number} y - Y-coordinate of the point\n * @param {array} segments - Array of boundary segments\n * @returns {boolean} True if the point is inside the polygon\n */\nfunction pointInsidePolygon(x, y, segments) {\n let inside = false;\n for (let i = 0; i < segments.length; i++) {\n const [[x1, y1], [x2, y2]] = segments[i];\n const intersect = y1 > y !== y2 > y && x < ((x2 - x1) * (y - y1)) / (y2 - y1) + x1;\n if (intersect) inside = !inside;\n }\n return inside;\n}\n","/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\"; //TODO rename importGmshQuadTri to importGmsh\nexport { logSystem } from \"./utilities/loggingScript.js\";\nexport { plotSolution, plotInterpolatedSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const printVersion = \"0.2.0 (RC)\";"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","logSystem","level","console","log","basicLog","debugLog","message","errorLog","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","value","serialized","Error","isError","name","stack","Object","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","map","fromWireValue","returnValue","parent","slice","reduce","prop","rawValue","apply","proxy","transfers","transferCache","set","transfer","undefined","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","constructor","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","Array","prototype","concat","handler","serializedValue","msg","fill","floor","random","Number","MAX_SAFE_INTEGER","join","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","jacobianMatrixSparse","math","sparse","luFactorization","slu","solutionMatrix","lusolve","squeeze","valueOf","jacobiSolverResult","A","b","x0","n","x","xNew","iter","sum","j","maxDiff","max","abs","jacobiSolver","timeEnd","async","solveLinearSystemAsync","isArray","toArray","created","computeEngine","worker","Worker","URL","url","Comlink.wrap","initialize","createDefaultComputeEngine","result","webgpuJacobiSolver","destroy","terminate","BasisFunctions","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","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elementIndex","gmshNodes","FEAScriptNodes","push","physicalPropMap","boundaryElements","fixedBoundaryElements","boundaryNodePairs","forEach","dimension","tag","nodesPair","node1","node2","foundElement","elementConnectivity","includes","side","node1Index","indexOf","node2Index","Mesh1D","super","generateMesh","nodesXCoordinates","totalNodesX","deltaX","nodeIndex","generateNodalNumbering1D","findBoundaryElements","nop","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generateNodalNumbering2D","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","prepareMesh","meshConfig","mesh","nodesCoordinatesAndNumbering","totalElements","totalNodes","initializeFEA","meshData","colIndex","basisFunctions","gaussPointsAndWeights","localToGlobalMap","nodesPerElement","performIsoparametricMapping1D","params","xCoordinates","ksiDerivX","localNodeIndex","detJacobian","basisFunctionDerivX","performIsoparametricMapping2D","yCoordinates","etaDerivX","ksiDerivY","etaDerivY","basisFunctionDerivY","pointInsideTriangle","y","vertices","v0","v1","v2","denom","inside","pointInsideQuadrilateral","firstTriangleVertices","secondTriangleVertices","v3","splitQuadrilateral","pointInsideFirstTriangle","pointInsideSecondTriangle","getDistanceFromLine","p1","p2","distLeft","distRight","distBottom","ThermalBoundaryConditions","boundaryConditions","imposeConstantTempBoundaryConditions","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","localResidualVector","boundaryElement","find","boundaryElementIndex","_","assembleHeatConductionMat","FEAData","gaussPointIndex1","mappingResult","localNodeIndex1","localToGlobalMap1","localToGlobalMap2","gaussPointIndex2","thermalBoundaryConditions","assembleHeatConductionFront","ngl","globalIndex","GenericBoundaryConditions","imposeDirichletBoundaryConditions","imposeConstantValueBoundaryConditionsFront","assembleFrontPropagationMat","eikonalActivationFlag","eikonalViscousTerm","solutionDerivX","solutionDerivY","assembleFrontPropagationFront","frontalData","frontalState","elementData","currentElementIndex","frontStorage","runFrontalSolver","assembleFront","numElements","globalResidualVector","topologyData","lateralData","writeFlag","transformationFlag","determinant","systemSize","globalSolutionVector","frontDataIndex","frontSize","frontWidthEstimate","ceil","estimateFrontSize","frontValues","columnHeaders","pivotRow","pivotData","initializeFrontalArrays","dirichletBoundaryConditionsHandler","currentSolutionVector","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","nodesCoordinates","boundaryLocalJacobianMatrix","boundaryResidualVector","isOnRobinTypeBoundary","some","localNodeI","localNodeJ","iterationIndex","accumulatedValue","newtonRaphson","assembleMat","context","errorNorm","initialSolution","FEAScriptModel","solverConfig","coefficientFunctions","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","eikonalExteralIterations","newtonRaphsonResult","B","C","D","xCoord","a","d","globalNodeIndex1","assembleGeneralFormPDEMat","solveAsync","importGmshQuadTri","file","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","numNodes","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","parseInt","replace","parametric","nodeTag","nodeIndices","idx","physicalTag","boundaryNodes","nodes","plotSolution","model","plotType","plotDivId","yData","from","lineData","mode","color","width","maxWindowWidth","min","window","innerWidth","layout","title","height","xaxis","yaxis","margin","l","t","Plotly","newPlot","responsive","zData","aspectRatio","plotWidth","hovermode","contourData","z","smoothing","contours","coloring","showlabels","colorbar","plotInterpolatedSolution","visNodeXCoordinates","visNodeYCoordinates","visSolution","visNodesX","visNodesY","deltavisX","deltavisY","visNodeIndexY","visNodeIndexX","boundarySegments","boundarySides","boundaryLineElements","boundaryNodesSegments","boundaryGlobalElementIndex","boundaryIndex","boundaryLocalElementIndex","boundaryLocalNodeIndices","currentElementNodesX","currentElementNodesY","boundaryLocalNodeIndex","k","getBoundarySegments","nodeNeighbors","neighborCount","elemIndex","computeNodeNeighbors","lastParentElement","visNodeIndex","pointInsidePolygon","found","neighborElementsIndex","searchResult","pointSearch","plotHeight","visNodeXCoordinate","visNodeYCoordinate","pointCheck","solutionInterpolation","solutionInterpolationValue","segments","x1","y1","x2","y2","FEAScriptWorker","feaWorker","isReady","_initWorker","onerror","event","workerWrapper","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","toFixed","getModelInfo","ping","printVersion"],"mappings":"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"} diff --git a/dist/feascript.umd.js b/dist/feascript.umd.js index 8edc4f6..1fd62f2 100644 --- a/dist/feascript.umd.js +++ b/dist/feascript.umd.js @@ -4,5 +4,5 @@ function _loadWasmModule(e,t,n){for(var o=t.length,s="="==t[o-2]?2:"="==t[o-1]?1 * Copyright 2019 Google LLC * SPDX-License-Identifier: Apache-2.0 */ -const r=Symbol("Comlink.proxy"),a=Symbol("Comlink.endpoint"),l=Symbol("Comlink.releaseProxy"),d=Symbol("Comlink.finalizer"),c=Symbol("Comlink.thrown"),u=e=>"object"==typeof e&&null!==e||"function"==typeof e,m=new Map([["proxy",{canHandle:e=>u(e)&&e[r],serialize(e){const{port1:t,port2:n}=new MessageChannel;return h(e,t),[n,[n]]},deserialize:e=>(e.start(),p(e))}],["throw",{canHandle:e=>u(e)&&c 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 h(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:a,path:l}=Object.assign({path:[]},s.data),u=(s.data.argumentList||[]).map(D);let m;try{const t=l.slice(0,-1).reduce(((e,t)=>e[t]),e),n=l.reduce(((e,t)=>e[t]),e);switch(a){case"GET":m=n;break;case"SET":t[l.slice(-1)[0]]=D(s.data.value),m=!0;break;case"APPLY":m=n.apply(t,u);break;case"CONSTRUCT":m=function(e){return Object.assign(e,{[r]:!0})}(new n(...u));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;h(e,n),m=function(e,t){return M.set(e,t),e}(t,[t])}break;case"RELEASE":m=void 0;break;default:return}}catch(e){m={value:e,[c]:0}}Promise.resolve(m).catch((e=>({value:e,[c]:0}))).then((n=>{const[s,r]=$(n);t.postMessage(Object.assign(Object.assign({},s),{id:i}),r),"RELEASE"===a&&(t.removeEventListener("message",o),f(t),d in e&&"function"==typeof e[d]&&e[d]())})).catch((e=>{const[n,o]=$({value:new TypeError("Unserializable return value"),[c]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),o)}))})),t.start&&t.start()}function f(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function p(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)}})),v(e,n,[],t)}function b(e){if(e)throw new Error("Proxy has been released and is not useable")}function g(e){return F(e,new Map,{type:"RELEASE"}).then((()=>{f(e)}))}const y=new WeakMap,E="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(y.get(e)||0)-1;y.set(e,t),0===t&&g(e)}));function v(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(b(s),r===l)return()=>{!function(e){E&&E.unregister(e)}(i),g(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=F(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then(D);return o.then.bind(o)}return v(e,t,[...n,r])},set(o,i,r){b(s);const[a,l]=$(r);return F(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then(D)},apply(o,i,r){b(s);const l=n[n.length-1];if(l===a)return F(e,t,{type:"ENDPOINT"}).then(D);if("bind"===l)return v(e,t,n.slice(0,-1));const[d,c]=C(r);return F(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:d},c).then(D)},construct(o,i){b(s);const[r,a]=C(i);return F(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then(D)}});return function(e,t){const n=(y.get(t)||0)+1;y.set(t,n),E&&E.register(e,t,e)}(i,e),i}function C(e){const t=e.map($);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const M=new WeakMap;function $(e){for(const[t,n]of m)if(n.canHandle(e)){const[o,s]=n.serialize(e);return[{type:"HANDLER",name:t,value:o},s]}return[{type:"RAW",value:e},M.get(e)||[]]}function D(e){switch(e.type){case"HANDLER":return m.get(e.name).deserialize(e.value);case"RAW":return e.value}}function F(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)}))}function A(e,t,n,r={}){const{maxIterations:a=1e4,tolerance:l=1e-4}=r;let d=[],c=!0,u=0;if(s(`Solving system using ${e}...`),console.time("systemSolving"),"lusolve"===e){const e=math.sparse(t),o=math.slu(e,1,1);let s=math.lusolve(o,n);d=math.squeeze(s).valueOf()}else if("jacobi"===e){const e=function(e,t,n,o={}){const{maxIterations:s,tolerance:i}=o,r=e.length;let a=[...n],l=new Array(r);for(let n=0;n{}))),m.worker.terminate()),{solutionVector:f,converged:b,iterations:u}}class w{constructor({meshDimension:e,elementOrder:t}){this.meshDimension=e,this.elementOrder=t}getBasisFunctions(e,t=null){let n=[],o=[],s=[];if("1D"===this.meshDimension)"linear"===this.elementOrder?(n[0]=1-e,n[1]=e,o[0]=-1,o[1]=1):"quadratic"===this.elementOrder&&(n[0]=1-3*e+2*e**2,n[1]=4*e-4*e**2,n[2]=2*e**2-e,o[0]=4*e-3,o[1]=4-8*e,o[2]=4*e-1);else if("2D"===this.meshDimension){if(null===t)return void i("Eta coordinate is required for 2D elements");if("linear"===this.elementOrder){function r(e){return 1-e}n[0]=r(e)*r(t),n[1]=r(e)*t,n[2]=e*r(t),n[3]=e*t,o[0]=-1*r(t),o[1]=-1*t,o[2]=1*r(t),o[3]=1*t,s[0]=-1*r(e),s[1]=1*r(e),s[2]=-1*e,s[3]=1*e}else if("quadratic"===this.elementOrder){function a(e){return 2*e**2-3*e+1}function l(e){return-4*e**2+4*e}function d(e){return 2*e**2-e}function c(e){return 4*e-3}function u(e){return-8*e+4}function m(e){return 4*e-1}n[0]=a(e)*a(t),n[1]=a(e)*l(t),n[2]=a(e)*d(t),n[3]=l(e)*a(t),n[4]=l(e)*l(t),n[5]=l(e)*d(t),n[6]=d(e)*a(t),n[7]=d(e)*l(t),n[8]=d(e)*d(t),o[0]=c(e)*a(t),o[1]=c(e)*l(t),o[2]=c(e)*d(t),o[3]=u(e)*a(t),o[4]=u(e)*l(t),o[5]=u(e)*d(t),o[6]=m(e)*a(t),o[7]=m(e)*l(t),o[8]=m(e)*d(t),s[0]=a(e)*c(t),s[1]=a(e)*u(t),s[2]=a(e)*m(t),s[3]=l(e)*c(t),s[4]=l(e)*u(t),s[5]=l(e)*m(t),s[6]=d(e)*c(t),s[7]=d(e)*u(t),s[8]=d(e)*m(t)}}return{basisFunction:n,basisFunctionDerivKsi:o,basisFunctionDerivEta:s}}}class N{constructor({numElementsX:e=null,maxX:t=null,numElementsY:n=null,maxY:o=null,meshDimension:i=null,elementOrder:r="linear",parsedMesh:a=null}){this.numElementsX=e,this.numElementsY=n,this.maxX=t,this.maxY=o,this.meshDimension=i,this.elementOrder=r,this.parsedMesh=a,this.boundaryElementsProcessed=!1,this.parsedMesh&&(s("Using pre-parsed mesh from gmshReader data for mesh generation."),this.parseMeshFromGmsh())}parseMeshFromGmsh(){if(this.parsedMesh.nodalNumbering||i("No valid nodal numbering found in the parsed mesh."),"object"==typeof this.parsedMesh.nodalNumbering&&!Array.isArray(this.parsedMesh.nodalNumbering)){const e=this.parsedMesh.nodalNumbering.quadElements||[];if(this.parsedMesh.nodalNumbering.triangleElements,o("Initial parsed mesh nodal numbering from GMSH format: "+JSON.stringify(this.parsedMesh.nodalNumbering)),this.parsedMesh.elementTypes[3]||this.parsedMesh.elementTypes[10]){const t=[];for(let n=0;n0&&void 0===this.parsedMesh.boundaryElements[0]){const e=[];for(let t=1;t{if(1===e.dimension){const t=this.parsedMesh.boundaryNodePairs[e.tag]||[];t.length>0&&(this.parsedMesh.boundaryElements[e.tag]||(this.parsedMesh.boundaryElements[e.tag]=[]),t.forEach((t=>{const n=t[0],s=t[1];o(`Processing boundary node pair: [${n}, ${s}] for boundary ${e.tag} (${e.name||"unnamed"})`);let r=!1;for(let t=0;t0&&void 0===this.parsedMesh.boundaryElements[0])){const e=[];for(let t=1;t{if("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((c=>{if("convection"===this.boundaryConditions[c][0]){const u=l[c],m=d[c];o(`Boundary ${c}: Applying convection with heat transfer coefficient h=${u} W/(m²·K) and external temperature T∞=${m} K`),this.boundaryElements[c].forEach((([l,d])=>{if("linear"===this.elementOrder){let c,h,f,p,b;0===d?(c=n[0],h=0,f=0,p=3,b=2):1===d?(c=0,h=n[0],f=0,p=2,b=1):2===d?(c=n[0],h=1,f=1,p=4,b=2):3===d&&(c=1,h=n[0],f=2,p=4,b=1);let g=a.getBasisFunctions(c,h),y=g.basisFunction,E=g.basisFunctionDerivKsi,v=g.basisFunctionDerivEta,C=0,M=0,$=0,D=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,c=Array(d).fill().map((()=>Array(d).fill(0))),u=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})`),u[t]+=-h*f,c[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 g=r.getBasisFunctions(o,l),y=g.basisFunction,E=g.basisFunctionDerivKsi,v=g.basisFunctionDerivEta;let C,M=0,$=0,D=0,F=0;for(let o=0;oArray(a).fill(0))),m=Array(a).fill(0),h=Array(a),f=Array(a);for(let n=0;ne-1)),{detJacobian:f,basisFunctionDerivX:p,basisFunctionDerivY:b}=I({basisFunction:n,basisFunctionDerivKsi:s,basisFunctionDerivEta:c,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 W(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:c,totalElements:u,meshDimension:m,elementOrder:h}=e,f=T(e),{residualVector:p,jacobianMatrix:b,localToGlobalMap:g,basisFunctions:y,gaussPoints:E,gaussWeights:v,numNodes:C}=f;for(let e=0;eArray(d).fill(0))),p=Array(d).fill(0),b=Array(d),g=Array(d);for(let n=0;nArray(e).fill(0))),q.nodeConstraintCode=Array(e).fill(0),q.boundaryValues=Array(e).fill(0),q.globalResidualVector=Array(e).fill(0),q.solutionVector=Array(e).fill(0),q.topologyData=Array(t).fill(0),q.lateralData=Array(t).fill(0),G.writeFlag=0,G.totalNodes=e,G.transformationFlag=0,G.nodesPerElement=Array(t).fill(0),G.determinant=1;const n=Math.max(e,2e3);G.globalSolutionVector=Array(n).fill(0),G.frontDataIndex=0,K.localJacobianMatrix=Array(e).fill().map((()=>Array(e).fill(0))),K.currentElementIndex=0;const o=function(e,t){const n=Math.max(Math.ceil(Math.sqrt(t))*e,2*e);return n*t}(e,t);J.frontValues=Array(o).fill(0),J.columnHeaders=Array(n).fill(0),J.pivotRow=Array(n).fill(0),J.pivotData=Array(o).fill(0)}(a.numNodes,d),s("Solving system using frontal..."),console.time("systemSolving"),H=new w({meshDimension:t.meshDimension,elementOrder:t.elementOrder});for(let e=0;eArray(l).fill(0))),y=Array(a).fill(0),E=Array(a).fill(0),v=Array(a).fill(0),C=1;G.writeFlag++;let M=1,$=1;K.currentElementIndex=0;for(let e=0;el||D>l)return void i("Error: systemSize not large enough");for(let e=0;e0)for(let e=0;e$||K.currentElementIndexMath.abs(n)&&(n=r,t=s,e=i)}}}let s=Math.abs(m[e-1]);d=Math.abs(J.columnHeaders[t-1]);let a=s+d+y[s-1]+E[d-1];G.determinant=G.determinant*n*(-1)**a/Math.abs(n);for(let e=0;e=s&&y[e]--,e>=d&&E[e]--;if(Math.abs(n)<1e-10&&i(`Matrix singular or ill-conditioned, currentElementIndex=${K.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||K.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:q.nodalNumbering,meshData:e,basisFunctions:H,FEAData:t,solutionVector:G.currentSolutionVector,eikonalActivationFlag:G.eikonalActivationFlag});let d=Array(t.numNodes).fill().map((()=>Array(t.numNodes).fill(0))),c=Array(t.numNodes).fill(0);if(o===Y){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,H);d=r.localJacobianMatrix,c=r.localResidualVector}}for(let e=0;e0)continue;let r=0;J.pivotRow[s-1]=0;for(let e=0;e100){i(`Solution not converged. Error norm: ${o}`);break}a++}return{solutionVector:d,converged:r,iterations:a,jacobianMatrix:c,residualVector:u}}e.FEAScriptModel=class{constructor(){var e;this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",this.coefficientFunctions=null,e="FEAScript is provided “as is” without any warranty. The authors are not responsible for any damages or losses that may result from using the software. See the license for more details: https://github.com/FEAScript/FEAScript-core/blob/main/LICENSE",console.log("%c[WARN] "+e,"color: #FF9800; font-weight: bold;"),s("FEAScriptModel instance created")}setSolverConfig(e,t={}){this.solverConfig=e,t?.coefficientFunctions&&(this.coefficientFunctions=t.coefficientFunctions,o("Coefficient functions set")),void 0!==t?.maxIterations&&(this.maxIterations=t.maxIterations),void 0!==t?.tolerance&&(this.tolerance=t.tolerance),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(e={}){this.solverConfig&&this.meshConfig&&this.boundaryConditions||i("Solver config, mesh config, and boundary conditions must be set before solving.");let t=[],n=[],o=[],r=[];s("Preparing mesh...");const a=V(this.meshConfig);s("Mesh preparation completed");const l={nodesXCoordinates:a.nodesXCoordinates,nodesYCoordinates:a.nodesYCoordinates};if(s("Beginning solving process..."),console.time("totalSolvingTime"),s(`Using solver: ${this.solverConfig}`),"heatConductionScript"===this.solverConfig)if("frontal"===this.solverMethod){o=L(Y,a,this.boundaryConditions).solutionVector}else{({jacobianMatrix:t,residualVector:n}=P(a,this.boundaryConditions));o=A(this.solverMethod,t,n,{maxIterations:e.maxIterations??this.maxIterations,tolerance:e.tolerance??this.tolerance}).solutionVector}else if("frontPropagationScript"===this.solverConfig){let s=0;const i=5,l={meshData:a,boundaryConditions:this.boundaryConditions,eikonalActivationFlag:s,solverMethod:this.solverMethod,initialSolution:r,maxIterations:e.maxIterations??this.maxIterations,tolerance:e.tolerance??this.tolerance};for(;s<=1;){l.eikonalActivationFlag=s,o.length>0&&(l.initialSolution=[...o]);const e=z(W,l);t=e.jacobianMatrix,n=e.residualVector,o=e.solutionVector,s+=1/i}}else if("generalFormPDEScript"===this.solverConfig)if("frontal"===this.solverMethod)i("Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.");else{({jacobianMatrix:t,residualVector:n}=function(e,t,n){s("Starting general form PDE matrix assembly...");const{nodesXCoordinates:o,nodesYCoordinates:r,nop:a,boundaryElements:l,totalElements:d,meshDimension:c,elementOrder:u}=e,{A:m,B:h,C:f,D:p}=n,b=T(e),{residualVector:g,jacobianMatrix:y,localToGlobalMap:E,basisFunctions:v,gaussPoints:C,gaussWeights:M,numNodes:$}=b;if("1D"===c)for(let e=0;e{console.error("FEAScriptWorker: Worker error:",e)};const e=p(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},c=0,u=[],m=0,h=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},b=0,g={};for(;i""!==e));if("meshFormat"===s)t.gmshV=parseFloat(o[0]),t.ascii="0"===o[1],t.fltBytes=o[2];else if("physicalNames"===s){if(o.length>=3){if(!/^\d+$/.test(o[0])){i++;continue}const e=parseInt(o[0],10),n=parseInt(o[1],10);let s=o.slice(2).join(" ");s=s.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:n,dimension:e,name:s})}}else if("nodes"===s){if(0===r){r=parseInt(o[0],10),a=parseInt(o[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;g[n]||(g[n]=[]),g[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);b++,b===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=g[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),o(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t},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){const{nodesXCoordinates:r,nodesYCoordinates:a}=t;if("1D"===o&&"line"===s){let t;t=e.length>0&&Array.isArray(e[0])?e.map((e=>e[0])):e,Array.from(r);let o={x:r,y:t,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},s=Math.min(window.innerWidth,700),a={title:`line plot - ${n}`,width:Math.min(s,600),height:350,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:50,r:50,t:50,b:50}};Plotly.newPlot(i,[o],a,{responsive:!0})}else if("2D"===o&&"contour"===s){let t;t=Array.isArray(e[0])?e.map((e=>e[0])):e;let o=Math.min(window.innerWidth,700),l=Math.max(...r),d=Math.max(...a)/l,c=Math.min(o,600),u={title:`${s} plot - ${n}`,width:c,height:c*d,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"},m={x:r,y:a,z:t,type:"contour",line:{smoothing:.85},contours:{coloring:"heatmap",showlabels:!1},colorbar:{title:"Solution"},name:"Solution Field"};Plotly.newPlot(i,[m],u,{responsive:!0})}},e.printVersion="0.1.4",Object.defineProperty(e,"__esModule",{value:!0})})); +const r=Symbol("Comlink.proxy"),a=Symbol("Comlink.endpoint"),l=Symbol("Comlink.releaseProxy"),d=Symbol("Comlink.finalizer"),c=Symbol("Comlink.thrown"),u=e=>"object"==typeof e&&null!==e||"function"==typeof e,m=new Map([["proxy",{canHandle:e=>u(e)&&e[r],serialize(e){const{port1:t,port2:n}=new MessageChannel;return h(e,t),[n,[n]]},deserialize:e=>(e.start(),p(e))}],["throw",{canHandle:e=>u(e)&&c 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 h(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:a,path:l}=Object.assign({path:[]},s.data),u=(s.data.argumentList||[]).map($);let m;try{const t=l.slice(0,-1).reduce(((e,t)=>e[t]),e),n=l.reduce(((e,t)=>e[t]),e);switch(a){case"GET":m=n;break;case"SET":t[l.slice(-1)[0]]=$(s.data.value),m=!0;break;case"APPLY":m=n.apply(t,u);break;case"CONSTRUCT":m=function(e){return Object.assign(e,{[r]:!0})}(new n(...u));break;case"ENDPOINT":{const{port1:t,port2:n}=new MessageChannel;h(e,n),m=function(e,t){return M.set(e,t),e}(t,[t])}break;case"RELEASE":m=void 0;break;default:return}}catch(e){m={value:e,[c]:0}}Promise.resolve(m).catch((e=>({value:e,[c]:0}))).then((n=>{const[s,r]=D(n);t.postMessage(Object.assign(Object.assign({},s),{id:i}),r),"RELEASE"===a&&(t.removeEventListener("message",o),f(t),d in e&&"function"==typeof e[d]&&e[d]())})).catch((e=>{const[n,o]=D({value:new TypeError("Unserializable return value"),[c]:0});t.postMessage(Object.assign(Object.assign({},n),{id:i}),o)}))})),t.start&&t.start()}function f(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function p(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)}})),v(e,n,[],t)}function b(e){if(e)throw new Error("Proxy has been released and is not useable")}function g(e){return F(e,new Map,{type:"RELEASE"}).then((()=>{f(e)}))}const y=new WeakMap,E="FinalizationRegistry"in globalThis&&new FinalizationRegistry((e=>{const t=(y.get(e)||0)-1;y.set(e,t),0===t&&g(e)}));function v(e,t,n=[],o=function(){}){let s=!1;const i=new Proxy(o,{get(o,r){if(b(s),r===l)return()=>{!function(e){E&&E.unregister(e)}(i),g(e),t.clear(),s=!0};if("then"===r){if(0===n.length)return{then:()=>i};const o=F(e,t,{type:"GET",path:n.map((e=>e.toString()))}).then($);return o.then.bind(o)}return v(e,t,[...n,r])},set(o,i,r){b(s);const[a,l]=D(r);return F(e,t,{type:"SET",path:[...n,i].map((e=>e.toString())),value:a},l).then($)},apply(o,i,r){b(s);const l=n[n.length-1];if(l===a)return F(e,t,{type:"ENDPOINT"}).then($);if("bind"===l)return v(e,t,n.slice(0,-1));const[d,c]=C(r);return F(e,t,{type:"APPLY",path:n.map((e=>e.toString())),argumentList:d},c).then($)},construct(o,i){b(s);const[r,a]=C(i);return F(e,t,{type:"CONSTRUCT",path:n.map((e=>e.toString())),argumentList:r},a).then($)}});return function(e,t){const n=(y.get(t)||0)+1;y.set(t,n),E&&E.register(e,t,e)}(i,e),i}function C(e){const t=e.map(D);return[t.map((e=>e[0])),(n=t.map((e=>e[1])),Array.prototype.concat.apply([],n))];var n}const M=new WeakMap;function D(e){for(const[t,n]of m)if(n.canHandle(e)){const[o,s]=n.serialize(e);return[{type:"HANDLER",name:t,value:o},s]}return[{type:"RAW",value:e},M.get(e)||[]]}function $(e){switch(e.type){case"HANDLER":return m.get(e.name).deserialize(e.value);case"RAW":return e.value}}function F(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)}))}function A(e,t,n,r={}){const{maxIterations:a=1e4,tolerance:l=1e-4}=r;let d=[],c=!0,u=0;if(s(`Solving system using ${e}...`),console.time("systemSolving"),"lusolve"===e){const e=math.sparse(t),o=math.slu(e,1,1);let s=math.lusolve(o,n);d=math.squeeze(s).valueOf()}else if("jacobi"===e){const e=function(e,t,n,o={}){const{maxIterations:s,tolerance:i}=o,r=e.length;let a=[...n],l=new Array(r);for(let n=0;n{}))),m.worker.terminate()),{solutionVector:f,converged:b,iterations:u}}class w{constructor({meshDimension:e,elementOrder:t}){this.meshDimension=e,this.elementOrder=t}getBasisFunctions(e,t=null){let n=[],o=[],s=[];if("1D"===this.meshDimension)"linear"===this.elementOrder?(n[0]=1-e,n[1]=e,o[0]=-1,o[1]=1):"quadratic"===this.elementOrder&&(n[0]=1-3*e+2*e**2,n[1]=4*e-4*e**2,n[2]=2*e**2-e,o[0]=4*e-3,o[1]=4-8*e,o[2]=4*e-1);else if("2D"===this.meshDimension){if(null===t)return void i("Eta coordinate is required for 2D elements");if("linear"===this.elementOrder){function r(e){return 1-e}n[0]=r(e)*r(t),n[1]=r(e)*t,n[2]=e*r(t),n[3]=e*t,o[0]=-1*r(t),o[1]=-1*t,o[2]=1*r(t),o[3]=1*t,s[0]=-1*r(e),s[1]=1*r(e),s[2]=-1*e,s[3]=1*e}else if("quadratic"===this.elementOrder){function a(e){return 2*e**2-3*e+1}function l(e){return-4*e**2+4*e}function d(e){return 2*e**2-e}function c(e){return 4*e-3}function u(e){return-8*e+4}function m(e){return 4*e-1}n[0]=a(e)*a(t),n[1]=a(e)*l(t),n[2]=a(e)*d(t),n[3]=l(e)*a(t),n[4]=l(e)*l(t),n[5]=l(e)*d(t),n[6]=d(e)*a(t),n[7]=d(e)*l(t),n[8]=d(e)*d(t),o[0]=c(e)*a(t),o[1]=c(e)*l(t),o[2]=c(e)*d(t),o[3]=u(e)*a(t),o[4]=u(e)*l(t),o[5]=u(e)*d(t),o[6]=m(e)*a(t),o[7]=m(e)*l(t),o[8]=m(e)*d(t),s[0]=a(e)*c(t),s[1]=a(e)*u(t),s[2]=a(e)*m(t),s[3]=l(e)*c(t),s[4]=l(e)*u(t),s[5]=l(e)*m(t),s[6]=d(e)*c(t),s[7]=d(e)*u(t),s[8]=d(e)*m(t)}}return{basisFunction:n,basisFunctionDerivKsi:o,basisFunctionDerivEta:s}}}class S{constructor({numElementsX:e=null,maxX:t=null,numElementsY:n=null,maxY:o=null,meshDimension:i=null,elementOrder:r="linear",parsedMesh:a=null}){this.numElementsX=e,this.numElementsY=n,this.maxX=t,this.maxY=o,this.meshDimension=i,this.elementOrder=r,this.parsedMesh=a,this.boundaryElementsProcessed=!1,this.parsedMesh&&(s("Using pre-parsed mesh from gmshReader data for mesh generation."),this.parseMeshFromGmsh())}parseMeshFromGmsh(){if(this.parsedMesh.nodalNumbering||i("No valid nodal numbering found in the parsed mesh."),Array.isArray(this.parsedMesh.nodalNumbering))return this.boundaryElementsProcessed=!0,this.parsedMesh.boundaryElementsProcessed=!0,this.parsedMesh;if("object"==typeof this.parsedMesh.nodalNumbering&&!Array.isArray(this.parsedMesh.nodalNumbering)){const e=this.parsedMesh.nodalNumbering.quadElements||[];if(this.parsedMesh.nodalNumbering.triangleElements,o("Initial parsed mesh nodal numbering from Gmsh format: "+JSON.stringify(this.parsedMesh.nodalNumbering)),this.parsedMesh.elementTypes[3]||this.parsedMesh.elementTypes[10]){const t=[];for(let n=0;n0&&void 0===this.parsedMesh.boundaryElements[0]){const e=[];for(let t=1;t{if(1===e.dimension){const t=this.parsedMesh.boundaryNodePairs[e.tag]||[];t.length>0&&(this.parsedMesh.boundaryElements[e.tag]||(this.parsedMesh.boundaryElements[e.tag]=[]),t.forEach((t=>{const n=t[0],s=t[1];o(`Processing boundary node pair: [${n}, ${s}] for boundary ${e.tag} (${e.name||"unnamed"})`);let r=!1;for(let t=0;t0&&void 0===this.parsedMesh.boundaryElements[0])){const e=[];for(let t=1;t=-1e-12&&l>=-1e-12&&1-a-l>=-1e-12,ksi:a,eta:l}}function R(e,t,n){const[o,s]=function(e){const[t,n,o,s]=e;return[[t,n,s],[t,o,s]]}(n),i=I(e,t,o),r=I(e,t,s),a=i.inside||r.inside;let l=0,d=0;if(a){const[o,s,i,r]=n,a=(n,o)=>Math.abs((o[0]-n[0])*(n[1]-t)-(n[0]-e)*(o[1]-n[1]))/Math.sqrt((o[0]-n[0])**2+(o[1]-n[1])**2),c=a(o,s),u=a(i,r),m=a(o,i);l=c/(c+u),d=m/(m+a(s,r))}return{inside:a,ksi:l,eta:d}}class Y{constructor(e,t,n,o,s){this.boundaryConditions=e,this.boundaryElements=t,this.nop=n,this.meshDimension=o,this.elementOrder=s}imposeConstantTempBoundaryConditions(e,t){"1D"===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],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((c=>{if("convection"===this.boundaryConditions[c][0]){const u=l[c],m=d[c];o(`Boundary ${c}: Applying convection with heat transfer coefficient h=${u} W/(m²·K) and external temperature T∞=${m} K`),this.boundaryElements[c].forEach((([l,d])=>{if("linear"===this.elementOrder){let c,h,f,p,b;0===d?(c=n[0],h=0,f=0,p=3,b=2):1===d?(c=0,h=n[0],f=0,p=2,b=1):2===d?(c=n[0],h=1,f=1,p=4,b=2):3===d&&(c=1,h=n[0],f=2,p=4,b=1);let g=a.getBasisFunctions(c,h),y=g.basisFunction,E=g.basisFunctionDerivKsi,v=g.basisFunctionDerivEta,C=0,M=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,c=Array(d).fill().map((()=>Array(d).fill(0))),u=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})`),u[t]+=-h*f,c[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 g=r.getBasisFunctions(o,l),y=g.basisFunction,E=g.basisFunctionDerivKsi,v=g.basisFunctionDerivEta;let C,M=0,D=0,$=0,F=0;for(let o=0;oArray(a).fill(0))),m=Array(a).fill(0),h=Array(a),f=Array(a);for(let n=0;ne-1)),{detJacobian:f,basisFunctionDerivX:p,basisFunctionDerivY:b}=T({basisFunction:n,basisFunctionDerivKsi:s,basisFunctionDerivEta:c,nodesXCoordinates:l,nodesYCoordinates:d,localToGlobalMap:m,nodesPerElement: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 j(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:c,totalElements:u,meshDimension:m,elementOrder:h}=e,f=P(e),{residualVector:p,jacobianMatrix:b,localToGlobalMap:g,basisFunctions:y,gaussPoints:E,gaussWeights:v,nodesPerElement:C}=f;for(let e=0;eArray(d).fill(0))),p=Array(d).fill(0),b=Array(d),g=Array(d);for(let n=0;nArray(e).fill(0))),K.nodeConstraintCode=Array(e).fill(0),K.boundaryValues=Array(e).fill(0),K.globalResidualVector=Array(e).fill(0),K.solutionVector=Array(e).fill(0),K.topologyData=Array(t).fill(0),K.lateralData=Array(t).fill(0),J.writeFlag=0,J.totalNodes=e,J.transformationFlag=0,J.nodesPerElement=Array(t).fill(0),J.determinant=1;const n=Math.max(e,2e3);J.globalSolutionVector=Array(n).fill(0),J.frontDataIndex=0,L.localJacobianMatrix=Array(e).fill().map((()=>Array(e).fill(0))),L.currentElementIndex=0;const o=function(e,t){const n=Math.max(Math.ceil(Math.sqrt(t))*e,2*e);return n*t}(e,t);H.frontValues=Array(o).fill(0),H.columnHeaders=Array(n).fill(0),H.pivotRow=Array(n).fill(0),H.pivotData=Array(o).fill(0)}(a.nodesPerElement,d),s("Solving system using frontal..."),console.time("systemSolving"),U=new w({meshDimension:t.meshDimension,elementOrder:t.elementOrder});for(let e=0;eArray(l).fill(0))),y=Array(a).fill(0),E=Array(a).fill(0),v=Array(a).fill(0),C=1;J.writeFlag++;let M=1,D=1;L.currentElementIndex=0;for(let e=0;el||$>l)return void i("Error: systemSize not large enough");for(let e=0;e0)for(let e=0;eD||L.currentElementIndexMath.abs(n)&&(n=r,t=s,e=i)}}}let s=Math.abs(m[e-1]);d=Math.abs(H.columnHeaders[t-1]);let a=s+d+y[s-1]+E[d-1];J.determinant=J.determinant*n*(-1)**a/Math.abs(n);for(let e=0;e=s&&y[e]--,e>=d&&E[e]--;if(Math.abs(n)<1e-10&&i(`Matrix singular or ill-conditioned, currentElementIndex=${L.currentElementIndex}, pivotGlobalRowIndex=${s}, pivotColumnGlobalIndex=${d}, pivotValue=${n}`),0===n)return;for(let t=0;t<$;t++)H.pivotRow[t]=g[e-1][t]/n;let l=K.globalResidualVector[s-1]/n;if(K.globalResidualVector[s-1]=l,b[e-1]=n,e>1)for(let n=0;n1&&0!==o)for(let e=0;e1)for(let e=0;e1||L.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:K.nodalNumbering,meshData:e,basisFunctions:U,FEAData:t,solutionVector:J.currentSolutionVector,eikonalActivationFlag:J.eikonalActivationFlag});let d=Array(t.nodesPerElement).fill().map((()=>Array(t.nodesPerElement).fill(0))),c=Array(t.nodesPerElement).fill(0);if(o===W){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,U);d=r.localJacobianMatrix,c=r.localResidualVector}}for(let e=0;e0)continue;let r=0;H.pivotRow[s-1]=0;for(let e=0;e100){i(`Solution not converged. Error norm: ${o}`);break}a++}return{solutionVector:d,converged:r,iterations:a,jacobianMatrix:c,residualVector:u}}function ee(e,t,n,o,s,i,r){const{nodesXCoordinates:a,nodesYCoordinates:l}=n.nodesCoordinates,d=t.nop[o].length;if(4===d){const d=R(s,i,[[a[t.nop[o][0]-1],l[t.nop[o][0]-1]],[a[t.nop[o][1]-1],l[t.nop[o][1]-1]],[a[t.nop[o][2]-1],l[t.nop[o][2]-1]],[a[t.nop[o][3]-1],l[t.nop[o][3]-1]]]);if(d.inside)return{inside:!0,value:te(e,t,n,o,d.ksi,d.eta,r)}}else if(9===d){const d=R(s,i,[[a[t.nop[o][0]-1],l[t.nop[o][0]-1]],[a[t.nop[o][2]-1],l[t.nop[o][2]-1]],[a[t.nop[o][6]-1],l[t.nop[o][6]-1]],[a[t.nop[o][8]-1],l[t.nop[o][8]-1]]]);if(d.inside)return{inside:!0,value:te(e,t,n,o,d.ksi,d.eta,r)}}return{inside:!1,value:null}}function te(e,t,n,o,s,i,r){const a=n.solutionVector,l=t.nop[o].length;let d,c=r.getBasisFunctions(s,i).basisFunction;d=Array.isArray(a[0])?a.map((e=>e[0])):a;let u=0;for(let e=0;et!=l>t&&e<(a-i)*(t-r)/(l-r)+i&&(o=!o)}return o}e.FEAScriptModel=class{constructor(){var e;this.solverConfig=null,this.meshConfig={},this.boundaryConditions={},this.solverMethod="lusolve",this.coefficientFunctions=null,e="FEAScript is provided “as is” without any warranty. The authors are not responsible for any damages or losses that may result from using the software. See the license for more details: https://github.com/FEAScript/FEAScript-core/blob/main/LICENSE",console.log("%c[WARN] "+e,"color: #FF9800; font-weight: bold;"),s("FEAScriptModel instance created")}setSolverConfig(e,t={}){this.solverConfig=e,t?.coefficientFunctions&&(this.coefficientFunctions=t.coefficientFunctions,o("Coefficient functions set")),void 0!==t?.maxIterations&&(this.maxIterations=t.maxIterations),void 0!==t?.tolerance&&(this.tolerance=t.tolerance),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(e={}){this.solverConfig&&this.meshConfig&&this.boundaryConditions||i("Solver config, mesh config, and boundary conditions must be set before solving.");let t=[],n=[],o=[],r=[];s("Preparing mesh...");const a=V(this.meshConfig);s("Mesh preparation completed");const l={nodesXCoordinates:a.nodesXCoordinates,nodesYCoordinates:a.nodesYCoordinates};if(s("Beginning solving process..."),console.time("totalSolvingTime"),s(`Using solver: ${this.solverConfig}`),"heatConductionScript"===this.solverConfig)if("frontal"===this.solverMethod){o=_(W,a,this.boundaryConditions).solutionVector}else{({jacobianMatrix:t,residualVector:n}=B(a,this.boundaryConditions));o=A(this.solverMethod,t,n,{maxIterations:e.maxIterations??this.maxIterations,tolerance:e.tolerance??this.tolerance}).solutionVector}else if("frontPropagationScript"===this.solverConfig){let s=0;const i=5,l={meshData:a,boundaryConditions:this.boundaryConditions,eikonalActivationFlag:s,solverMethod:this.solverMethod,initialSolution:r,maxIterations:e.maxIterations??this.maxIterations,tolerance:e.tolerance??this.tolerance};for(;s<=1;){l.eikonalActivationFlag=s,o.length>0&&(l.initialSolution=[...o]);const e=Z(j,l);t=e.jacobianMatrix,n=e.residualVector,o=e.solutionVector,s+=1/i}}else if("generalFormPDEScript"===this.solverConfig)if("frontal"===this.solverMethod)i("Frontal solver is not yet supported for generalFormPDEScript. Please use 'lusolve' or 'jacobi'.");else{({jacobianMatrix:t,residualVector:n}=function(e,t,n){s("Starting general form PDE matrix assembly...");const{nodesXCoordinates:o,nodesYCoordinates:r,nop:a,boundaryElements:l,totalElements:d,meshDimension:c,elementOrder:u}=e,{A:m,B:h,C:f,D:p}=n,b=P(e),{residualVector:g,jacobianMatrix:y,localToGlobalMap:E,basisFunctions:v,gaussPoints:C,gaussWeights:M,nodesPerElement:D}=b;if("1D"===c)for(let e=0;e{console.error("FEAScriptWorker: Worker error:",e)};const e=p(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},c=0,u=[],m=0,h=0,f=0,p={dim:0,tag:0,elementType:0,numElements:0},b=0,g={};for(;i""!==e));if("meshFormat"===s)t.gmshV=parseFloat(o[0]),t.ascii="0"===o[1],t.fltBytes=o[2];else if("physicalNames"===s){if(o.length>=3){if(!/^\d+$/.test(o[0])){i++;continue}const e=parseInt(o[0],10),n=parseInt(o[1],10);let s=o.slice(2).join(" ");s=s.replace(/^"|"$/g,""),t.physicalPropMap.push({tag:n,dimension:e,name:s})}}else if("nodes"===s){if(0===r){r=parseInt(o[0],10),a=parseInt(o[1],10),t.nodesXCoordinates=new Array(a).fill(0),t.nodesYCoordinates=new Array(a).fill(0),i++;continue}if(lparseInt(e,10)));if(1===p.elementType||8===p.elementType){const n=p.tag;g[n]||(g[n]=[]),g[n].push(e),t.boundaryNodePairs[n]||(t.boundaryNodePairs[n]=[]),t.boundaryNodePairs[n].push(e)}else 2===p.elementType?t.nodalNumbering.triangleElements.push(e):(3===p.elementType||10===p.elementType)&&t.nodalNumbering.quadElements.push(e);b++,b===p.numElements&&(f++,p={numElements:0})}}i++}return t.physicalPropMap.forEach((e=>{if(1===e.dimension){const n=g[e.tag]||[];n.length>0&&t.boundaryConditions.push({name:e.name,tag:e.tag,nodes:n})}})),o(`Parsed boundary node pairs by physical tag: ${JSON.stringify(t.boundaryNodePairs)}. These pairs will be used to identify boundary elements in the mesh.`),t},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.plotInterpolatedSolution=function(e,t,n,o){const{nodesXCoordinates:s,nodesYCoordinates:i}=t.nodesCoordinates,r=e.meshConfig.meshDimension,a=V(e.meshConfig),l=new w({meshDimension:e.meshConfig.meshDimension,elementOrder:e.meshConfig.elementOrder});if("1D"===r&&"line"===n);else if("2D"===r&&"contour"===n){const r=[],d=[];let c=[];const u=100,m=100,h=(Math.max(...s)-Math.min(...s))/(u-1),f=(Math.max(...i)-Math.min(...i))/(m-1);r[0]=Math.min(...s),d[0]=Math.min(...i);for(let e=1;e[])),r=Array(o).fill(0);for(let e=0;e0&&Array.isArray(r[0])?r.map((e=>e[0])):r,Array.from(s);let t={x:s,y:e,mode:"lines",type:"scatter",line:{color:"rgb(219, 64, 82)",width:2},name:"Solution"},n=Math.min(window.innerWidth,700),i={title:`line plot - ${a}`,width:Math.min(n,600),height:300,xaxis:{title:"x"},yaxis:{title:"Solution"},margin:{l:50,r:50,t:50,b:50}};Plotly.newPlot(o,[t],i,{responsive:!0})}else if("2D"===l&&"contour"===n){let e;e=Array.isArray(r[0])?r.map((e=>e[0])):r;let t=Math.min(window.innerWidth,700),l=Math.max(...s),d=Math.max(...i)/l,c=Math.min(t,600),u={title:`${n} plot - ${a}`,width:c,height:c*d,xaxis:{title:"x"},yaxis:{title:"y"},margin:{l:50,r:50,t:50,b:50},hovermode:"closest"},m={x:s,y:i,z:e,type:"contour",line:{smoothing:.85},contours:{coloring:"heatmap",showlabels:!1},colorbar:{title:"Solution"},name:"Solution Field"};Plotly.newPlot(o,[m],u,{responsive:!0})}},e.printVersion="0.2.0 (RC)",Object.defineProperty(e,"__esModule",{value:!0})})); //# sourceMappingURL=feascript.umd.js.map diff --git a/dist/feascript.umd.js.map b/dist/feascript.umd.js.map index 57328ff..896ab6c 100644 --- a/dist/feascript.umd.js.map +++ b/dist/feascript.umd.js.map @@ -1 +1 @@ -{"version":3,"file":"feascript.umd.js","sources":["../src/methods/euclideanNormScript.js","../src/utilities/loggingScript.js","../src/vendor/comlink.mjs","../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/models/thermalBoundaryConditionsScript.js","../src/models/heatConductionScript.js","../src/models/genericBoundaryConditionsScript.js","../src/models/frontPropagationScript.js","../src/methods/frontalSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/FEAScript.js","../src/models/generalFormPDEScript.js","../src/workers/workerScript.js","../src/readers/gmshReaderScript.js","../src/visualization/plotSolutionScript.js","../src/index.js"],"sourcesContent":["/**\n * ════════════════════════════════════════════════════════════\n * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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;\");\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;\");\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;\");\n}\n\n/**\n * Function to log warning messages\n * @param {string} message - Message to log\n */\nexport function warnLog(message) {\n console.log(\"%c[WARN] \" + message, \"color: #FF9800; font-weight: bold;\");\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 * @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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { jacobiSolver } from \"./jacobiSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\nimport * as Comlink from \"../vendor/comlink.mjs\";\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] - Optional parameters for the solver, such as `maxIterations` and `tolerance`\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\n // Extract options\n const { maxIterations = 10000, tolerance = 1e-4 } = 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// Helper to lazily create a default WebGPU compute engine (Comlink + worker)\nasync function createDefaultComputeEngine() {\n const worker = new Worker(new URL(\"../workers/webgpuWorkerScript.js\", import.meta.url), {\n type: \"module\",\n });\n const computeEngine = Comlink.wrap(worker);\n await computeEngine.initialize();\n return { computeEngine, worker };\n}\n\n/**\n * Function to solve asynchronously a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (e.g., \"jacobi-gpu\")\n * @param {array} jacobianMatrix - The coefficient matrix\n * @param {array} residualVector - The right-hand side vector\n * @param {object} [options] - Optional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {Promise} A promise that resolves to 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 async function solveLinearSystemAsync(solverMethod, jacobianMatrix, residualVector, options = {}) {\n \n // Extract options\n const { maxIterations = 10000, tolerance = 1e-4 } = options;\n\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n // Normalize inputs\n const A = Array.isArray(jacobianMatrix) ? jacobianMatrix : jacobianMatrix?.toArray?.() ?? jacobianMatrix;\n const b = Array.isArray(residualVector) ? residualVector : residualVector?.toArray?.() ?? residualVector;\n\n let created = null;\n let computeEngine = null;\n\n let solutionVector = [];\n let converged = true;\n let iterations;\n\n if (solverMethod === \"jacobi-gpu\") {\n // Spin up a worker-backed compute engine\n created = await createDefaultComputeEngine();\n computeEngine = created.computeEngine;\n\n const x0 = new Array(b.length).fill(0);\n let result;\n\n result = await computeEngine.webgpuJacobiSolver(A, b, x0, { maxIterations, tolerance });\n solutionVector = result.solutionVector;\n converged = result.converged;\n iterations = result.iterations;\n\n // Log convergence information\n if (converged) {\n debugLog(`Jacobi method converged in ${iterations} iterations`);\n } else {\n errorLog(`Jacobi method did not converge after ${iterations} iterations`);\n }\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(`System solved successfully (${solverMethod})`);\n\n if (created) {\n await computeEngine?.destroy?.().catch(() => { });\n created.worker.terminate();\n }\n\n return { solutionVector, converged, iterations };\n}\n","/**\n * ════════════════════════════════════════════════════════════\n * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method (CPU synchronous version)\n * @param {array} A - The system matrix\n * @param {array} b - The right-hand side vector\n * @param {array} x0 - Initial guess for solution vector\n * @param {object} [options] - Optional parameters for the solver, such as `maxIterations` and `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(A, b, x0, options = {}) {\n // Extract options\n const { maxIterations, tolerance } = options;\n\n const n = A.length;\n let x = [...x0];\n let xNew = new Array(n);\n\n // Jacobi update: xNew[i] = (b[i] - sum(A[i][j] * x[j] for j != i)) / A[i][i]\n for (let iter = 0; iter < maxIterations; iter++) {\n for (let i = 0; i < n; i++) {\n let sum = 0;\n for (let j = 0; j < n; j++) {\n if (i !== j) {\n sum += A[i][j] * x[j];\n }\n }\n xNew[i] = (b[i] - sum) / A[i][i];\n }\n\n // Check convergence based on maximum difference in solution vector\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 // Copy new solution for the next iteration\n x = [...xNew];\n\n if (maxDiff < tolerance) {\n return { solutionVector: x, iterations: iter + 1, converged: true };\n }\n }\n\n return { solutionVector: x, iterations: maxIterations, converged: false };\n}\n","/**\n * ════════════════════════════════════════════════════════════\n * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { initializeFEA } from \"../mesh/meshUtilsScript.js\";\nimport { assembleHeatConductionFront } from \"../models/heatConductionScript.js\";\nimport { ThermalBoundaryConditions } from \"../models/thermalBoundaryConditionsScript.js\";\nimport { assembleFrontPropagationFront } from \"../models/frontPropagationScript.js\";\nimport { GenericBoundaryConditions } from \"../models/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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 \"../models/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 * @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 = {}) {\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 // Extract context\n const { maxIterations = 100, tolerance = 1e-4 } = context;\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { solveLinearSystemAsync } from \"./methods/linearSystemSolverScript.js\";\nimport { prepareMesh } from \"./mesh/meshUtilsScript.js\";\nimport { assembleFrontPropagationMat } from \"./models/frontPropagationScript.js\";\nimport { assembleGeneralFormPDEMat, assembleGeneralFormPDEFront } from \"./models/generalFormPDEScript.js\";\nimport { assembleHeatConductionMat, assembleHeatConductionFront } from \"./models/heatConductionScript.js\";\nimport { runFrontalSolver } from \"./methods/frontalSolverScript.js\";\nimport { basicLog, debugLog, warnLog, 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 containifng 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 warnLog(\n \"FEAScript is provided “as is” without any warranty. The authors are not responsible for any damages or losses that may result from using the software. See the license for more details: https://github.com/FEAScript/FEAScript-core/blob/main/LICENSE\"\n );\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?.coefficientFunctions) {\n this.coefficientFunctions = options.coefficientFunctions;\n debugLog(\"Coefficient functions set\");\n }\n // Only update if a value is provided, otherwise keep the default\n if (options?.maxIterations !== undefined) {\n this.maxIterations = options.maxIterations;\n }\n if (options?.tolerance !== undefined) {\n this.tolerance = options.tolerance;\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 /**\n * Function to solve the finite element problem synchronously\n * @param {object} [options] - Additional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {object} An object containing the solution vector and the coordinates of the mesh nodes\n */\n solve(options = {}) {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n errorLog(\"Solver config, mesh config, and boundary conditions must be set before solving.\");\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 basicLog(`Using solver: ${this.solverConfig}`);\n if (this.solverConfig === \"heatConductionScript\") {\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 maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n });\n solutionVector = linearSystemResult.solutionVector;\n }\n } else if (this.solverConfig === \"frontPropagationScript\") {\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 // TODO: Consider using different maxIterations/tolerance for Newton-Raphson and linear solver\n maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\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);\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 // 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 maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n });\n solutionVector = linearSystemResult.solutionVector;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n\n /**\n * Function to solve the finite element problem asynchronously\n * @param {object} computeEngine - The compute engine to use for the asynchronous solver (e.g., a worker or a WebGPU context)\n * @param {object} [options] - Additional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {Promise} A promise that resolves to an object containing the solution vector and the coordinates of the mesh nodes\n */\n async solveAsync(computeEngine, options = {}) {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n errorLog(\"Solver config, mesh config, and boundary conditions must be set before solving.\");\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n\n basicLog(\"Preparing mesh...\");\n const meshData = prepareMesh(this.meshConfig);\n basicLog(\"Mesh preparation completed\");\n const nodesCoordinates = {\n nodesXCoordinates: meshData.nodesXCoordinates,\n nodesYCoordinates: meshData.nodesYCoordinates,\n };\n\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n\n basicLog(`Using solver: ${this.solverConfig}`);\n if (this.solverConfig === \"heatConductionScript\") {\n ({ jacobianMatrix, residualVector } = assembleHeatConductionMat(meshData, this.boundaryConditions));\n\n if (this.solverMethod === \"jacobi-gpu\") {\n const { solutionVector: x } = await solveLinearSystemAsync(\"jacobi-gpu\", jacobianMatrix, residualVector, {\n computeEngine,\n maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n });\n solutionVector = x;\n } else {\n // Other async solver\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n\n}\n","/**\n * ════════════════════════════════════════════════════════════\n * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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 */\nexport function plotSolution(\n solutionVector,\n nodesCoordinates,\n solverConfig,\n meshDimension,\n plotType,\n plotDivId\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: nodesXCoordinates,\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 plotWidth = Math.min(maxWindowWidth, 600);\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: 50, r: 50, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Check if solutionVector is a nested array\n let zData;\n if (Array.isArray(solutionVector[0])) {\n zData = solutionVector.map((val) => val[0]);\n } else {\n zData = solutionVector;\n }\n\n // Sizing parameters\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;\n\n // 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 // Create the plot\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zData,\n type: \"contour\",\n line: {\n smoothing: 0.85,\n },\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 Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n}\n","/**\n * ════════════════════════════════════════════════════════════\n * FEAScript Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.1.4 | https://feascript.com\n * ════════════════════════════════════════════════════════════\n */\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.4\";"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","debugLog","message","console","log","basicLog","errorLog","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","value","serialized","Error","isError","name","stack","Object","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","map","fromWireValue","returnValue","parent","slice","reduce","prop","rawValue","apply","proxy","transfers","transferCache","set","transfer","undefined","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","constructor","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","Array","prototype","concat","handler","serializedValue","msg","fill","floor","random","Number","MAX_SAFE_INTEGER","join","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","jacobianMatrixSparse","math","sparse","luFactorization","slu","solutionMatrix","lusolve","squeeze","valueOf","jacobiSolverResult","A","b","x0","n","x","xNew","iter","sum","j","maxDiff","max","abs","jacobiSolver","timeEnd","async","solveLinearSystemAsync","isArray","toArray","created","computeEngine","worker","Worker","URL","document","location","require","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","Comlink.wrap","initialize","createDefaultComputeEngine","result","webgpuJacobiSolver","destroy","terminate","BasisFunctions","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","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elemIdx","gmshNodes","feaScriptNodes","push","physicalPropMap","boundaryElements","fixedBoundaryElements","boundaryNodePairs","forEach","dimension","tag","nodesPair","node1","node2","foundElement","elemNodes","includes","side","node1Index","indexOf","node2Index","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","prepareMesh","meshConfig","mesh","nodesCoordinatesAndNumbering","totalElements","totalNodes","initializeFEA","meshData","colIndex","basisFunctions","gaussPointsAndWeights","localToGlobalMap","numNodes","performIsoparametricMapping1D","params","xCoordinates","ksiDerivX","localNodeIndex","detJacobian","basisFunctionDerivX","performIsoparametricMapping2D","yCoordinates","etaDerivX","ksiDerivY","etaDerivY","basisFunctionDerivY","ThermalBoundaryConditions","boundaryConditions","imposeConstantTempBoundaryConditions","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","localResidualVector","boundaryElement","find","_","assembleHeatConductionMat","FEAData","gaussPointIndex1","mappingResult","localNodeIndex1","localToGlobalMap1","localToGlobalMap2","gaussPointIndex2","thermalBoundaryConditions","assembleHeatConductionFront","ngl","globalIndex","GenericBoundaryConditions","imposeDirichletBoundaryConditions","imposeConstantValueBoundaryConditionsFront","assembleFrontPropagationMat","eikonalActivationFlag","eikonalViscousTerm","solutionDerivX","solutionDerivY","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","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","nodesCoordinates","boundaryLocalJacobianMatrix","boundaryResidualVector","isOnRobinTypeBoundary","some","localNodeI","localNodeJ","iterationIndex","accumulatedValue","newtonRaphson","assembleMat","context","errorNorm","initialSolution","solverConfig","coefficientFunctions","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","eikonalExteralIterations","newtonRaphsonResult","B","C","D","xCoord","a","d","globalNodeIndex1","assembleGeneralFormPDEMat","solveAsync","feaWorker","isReady","_initWorker","onerror","event","workerWrapper","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","toFixed","getModelInfo","ping","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","yData","from","lineData","mode","color","width","maxWindowWidth","min","window","innerWidth","layout","title","height","xaxis","yaxis","margin","l","t","Plotly","newPlot","responsive","zData","aspectRatio","plotWidth","hovermode","contourData","z","smoothing","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/vendor/comlink.mjs","../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/models/thermalBoundaryConditionsScript.js","../src/models/heatConductionScript.js","../src/models/genericBoundaryConditionsScript.js","../src/models/frontPropagationScript.js","../src/methods/frontalSolverScript.js","../src/methods/newtonRaphsonScript.js","../src/visualization/plotSolutionScript.js","../src/FEAScript.js","../src/models/generalFormPDEScript.js","../src/workers/workerScript.js","../src/readers/gmshReaderScript.js","../src/index.js"],"sourcesContent":["/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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;\");\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;\");\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;\");\n}\n\n/**\n * Function to log warning messages\n * @param {string} message - Message to log\n */\nexport function warnLog(message) {\n console.log(\"%c[WARN] \" + message, \"color: #FF9800; font-weight: bold;\");\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 * @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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { jacobiSolver } from \"./jacobiSolverScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\nimport * as Comlink from \"../vendor/comlink.mjs\";\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] - Optional parameters for the solver, such as `maxIterations` and `tolerance`\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\n // Extract options\n const { maxIterations = 10000, tolerance = 1e-4 } = 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// Helper to lazily create a default WebGPU compute engine (Comlink + worker)\nasync function createDefaultComputeEngine() {\n const worker = new Worker(new URL(\"../workers/webgpuWorkerScript.js\", import.meta.url), {\n type: \"module\",\n });\n const computeEngine = Comlink.wrap(worker);\n await computeEngine.initialize();\n return { computeEngine, worker };\n}\n\n/**\n * Function to solve asynchronously a system of linear equations using different solver methods\n * @param {string} solverMethod - The solver method to use (e.g., \"jacobi-gpu\")\n * @param {array} jacobianMatrix - The coefficient matrix\n * @param {array} residualVector - The right-hand side vector\n * @param {object} [options] - Optional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {Promise} A promise that resolves to 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 async function solveLinearSystemAsync(solverMethod, jacobianMatrix, residualVector, options = {}) {\n \n // Extract options\n const { maxIterations = 10000, tolerance = 1e-4 } = options;\n\n basicLog(`Solving system using ${solverMethod}...`);\n console.time(\"systemSolving\");\n\n // Normalize inputs\n const A = Array.isArray(jacobianMatrix) ? jacobianMatrix : jacobianMatrix?.toArray?.() ?? jacobianMatrix;\n const b = Array.isArray(residualVector) ? residualVector : residualVector?.toArray?.() ?? residualVector;\n\n let created = null;\n let computeEngine = null;\n\n let solutionVector = [];\n let converged = true;\n let iterations;\n\n if (solverMethod === \"jacobi-gpu\") {\n // Spin up a worker-backed compute engine\n created = await createDefaultComputeEngine();\n computeEngine = created.computeEngine;\n\n const x0 = new Array(b.length).fill(0);\n let result;\n\n result = await computeEngine.webgpuJacobiSolver(A, b, x0, { maxIterations, tolerance });\n solutionVector = result.solutionVector;\n converged = result.converged;\n iterations = result.iterations;\n\n // Log convergence information\n if (converged) {\n debugLog(`Jacobi method converged in ${iterations} iterations`);\n } else {\n errorLog(`Jacobi method did not converge after ${iterations} iterations`);\n }\n } else {\n errorLog(`Unknown solver method: ${solverMethod}`);\n }\n\n console.timeEnd(\"systemSolving\");\n basicLog(`System solved successfully (${solverMethod})`);\n\n if (created) {\n await computeEngine?.destroy?.().catch(() => { });\n created.worker.terminate();\n }\n\n return { solutionVector, converged, iterations };\n}\n","/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n/**\n * Function to solve a system of linear equations using the Jacobi iterative method (CPU synchronous version)\n * @param {array} A - The system matrix\n * @param {array} b - The right-hand side vector\n * @param {array} x0 - Initial guess for solution vector\n * @param {object} [options] - Optional parameters for the solver, such as `maxIterations` and `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(A, b, x0, options = {}) {\n // Extract options\n const { maxIterations, tolerance } = options;\n\n const n = A.length;\n let x = [...x0];\n let xNew = new Array(n);\n\n // Jacobi update: xNew[i] = (b[i] - sum(A[i][j] * x[j] for j != i)) / A[i][i]\n for (let iter = 0; iter < maxIterations; iter++) {\n for (let i = 0; i < n; i++) {\n let sum = 0;\n for (let j = 0; j < n; j++) {\n if (i !== j) {\n sum += A[i][j] * x[j];\n }\n }\n xNew[i] = (b[i] - sum) / A[i][i];\n }\n\n // Check convergence based on maximum difference in solution vector\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 // Copy new solution for the next iteration\n x = [...xNew];\n\n if (maxDiff < tolerance) {\n return { solutionVector: x, iterations: iter + 1, converged: true };\n }\n }\n\n return { solutionVector: x, iterations: maxIterations, converged: false };\n}\n","/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 this parsed mesh was already converted in a previous run, don't re-process it.\n // Just mark this Mesh instance as ready so prepareMesh() doesn't fall back to generateMesh().\n if (Array.isArray(this.parsedMesh.nodalNumbering)) {\n this.boundaryElementsProcessed = true;\n this.parsedMesh.boundaryElementsProcessed = true;\n return this.parsedMesh;\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 elementIndex = 0; elementIndex < quadElements.length; elementIndex++) {\n const gmshNodes = quadElements[elementIndex];\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 (\n let elementIndex = 0;\n elementIndex < this.parsedMesh.nodalNumbering.length;\n elementIndex++\n ) {\n const elementConnectivity = this.parsedMesh.nodalNumbering[elementIndex];\n\n // For linear quadrilateral linear elements (4 nodes)\n if (elementConnectivity.length === 4) {\n // Check if both boundary nodes are in this element\n if (elementConnectivity.includes(node1) && elementConnectivity.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elementConnectivity.indexOf(node1);\n const node2Index = elementConnectivity.indexOf(node2);\n\n debugLog(\n ` Found element ${elementIndex} containing boundary nodes. Element nodes: [${elementConnectivity.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 ${elementIndex}`);\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 ${elementIndex}`);\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 ${elementIndex}`);\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 ${elementIndex}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elementIndex, side]);\n debugLog(\n ` Added element-side pair [${elementIndex}, ${side}] to boundary tag ${prop.tag}`\n );\n foundElement = true;\n break;\n }\n } else if (elementConnectivity.length === 9) {\n // For quadratic quadrilateral elements (9 nodes)\n // Check if both boundary nodes are in this element\n if (elementConnectivity.includes(node1) && elementConnectivity.includes(node2)) {\n // Find which side of the element these nodes form\n let side;\n\n const node1Index = elementConnectivity.indexOf(node1);\n const node2Index = elementConnectivity.indexOf(node2);\n\n debugLog(\n ` Found element ${elementIndex} containing boundary nodes. Element nodes: [${elementConnectivity.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 ${elementIndex}`);\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 ${elementIndex}`);\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 ${elementIndex}`);\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 ${elementIndex}`);\n }\n\n // Add the element and side to the boundary elements array\n this.parsedMesh.boundaryElements[prop.tag].push([elementIndex, side]);\n debugLog(\n ` Added element-side pair [${elementIndex}, ${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.generateNodalNumbering1D(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 generateNodalNumbering1D(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 an 1D 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 * 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; // Two sides for 1D case (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.generateNodalNumbering2D(\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 generateNodalNumbering2D(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 2D 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 * 0 - Bottom side of reference element (maps to physical bottom boundary in the case of a rectangular domain)\n * 1 - Left side of reference element (maps to physical left boundary in the case of a rectangular domain)\n * 2 - Top side of reference element (maps to physical top boundary in the case of a rectangular domain)\n * 3 - Right side of reference element (maps to physical right boundary in the case of a rectangular domain)\n */\n findBoundaryElements() {\n const boundaryElements = [];\n const maxSides = 4; // Four sides for a rectangle 2D case (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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n// Internal imports\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 (e.g., from a Gmsh .msh import) if provided. Otherwise, generate a structured mesh\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 nodesPerElement = nop[0].length;\n\n return {\n residualVector,\n jacobianMatrix,\n localToGlobalMap,\n basisFunctions,\n gaussPoints,\n gaussWeights,\n nodesPerElement,\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, nodesPerElement } =\n params;\n\n let xCoordinates = 0;\n let ksiDerivX = 0;\n\n // Isoparametric mapping\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; 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 < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; 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 < nodesPerElement; 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 * Function to test if a point is inside a triangle using barycentric coordinates,\n * also returning the natural coordinates (ksi, eta).\n * @param {number} x - X-coordinate of the point\n * @param {number} y - Y-coordinate of the point\n * @param {array} vertices - Triangle vertices [[x0,y0],[x1,y1],[x2,y2]]\n * @returns {object} Object containing inside boolean and natural coordinates {inside, ksi, eta}\n */\nexport function pointInsideTriangle(x, y, vertices) {\n const tolerance = 1e-12;\n const [v0, v1, v2] = vertices;\n\n const denom = (v1[1] - v2[1]) * (v0[0] - v2[0]) + (v2[0] - v1[0]) * (v0[1] - v2[1]);\n\n const ksi = ((v1[1] - v2[1]) * (x - v2[0]) + (v2[0] - v1[0]) * (y - v2[1])) / denom;\n const eta = ((v2[1] - v0[1]) * (x - v2[0]) + (v0[0] - v2[0]) * (y - v2[1])) / denom;\n const gamma = 1 - ksi - eta;\n\n const inside = ksi >= -tolerance && eta >= -tolerance && gamma >= -tolerance;\n return { inside, ksi, eta };\n}\n\n/**\n * Function to test if a point is inside a quadrilateral by spliting it into triangles and using barycentric coordinates\n * @param {number} x - X-coordinate of the point\n * @param {number} y - Y-coordinate of the point\n * @param {array} vertices - Quadrilateral vertices [[x0,y0],[x1,y1],[x2,y2],[x3,y3]]\n * @returns {object} Object containing inside boolean and natural coordinates {inside, ksi, eta}\n */\nexport function pointInsideQuadrilateral(x, y, vertices) {\n const [firstTriangleVertices, secondTriangleVertices] = splitQuadrilateral(vertices);\n const pointInsideFirstTriangle = pointInsideTriangle(x, y, firstTriangleVertices);\n const pointInsideSecondTriangle = pointInsideTriangle(x, y, secondTriangleVertices);\n\n const inside = pointInsideFirstTriangle.inside || pointInsideSecondTriangle.inside;\n let ksi = 0;\n let eta = 0;\n\n if (inside) {\n const [v0, v1, v2, v3] = vertices;\n\n // Function to calculate distance from point to line segment\n const getDistanceFromLine = (p1, p2) => {\n const num = Math.abs((p2[0] - p1[0]) * (p1[1] - y) - (p1[0] - x) * (p2[1] - p1[1]));\n const den = Math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2);\n return num / den;\n };\n\n // Calculate distances to edges based on vertex order:\n // 1 (v1) --- 3 (v3)\n // | |\n // 0 (v0) --- 2 (v2)\n\n const distLeft = getDistanceFromLine(v0, v1);\n const distRight = getDistanceFromLine(v2, v3);\n const distBottom = getDistanceFromLine(v0, v2);\n const distTop = getDistanceFromLine(v1, v3);\n\n ksi = distLeft / (distLeft + distRight);\n eta = distBottom / (distBottom + distTop);\n }\n\n return { inside, ksi, eta };\n}\n\n/**\n * Function to split the quadrilateral elements into two triangles\n * @param {array} vertices - Quadrilateral vertices [[x0,y0],[x1,y1],[x2,y2],[x3,y3]]\n * @returns {array} Array of triangle vertices: [[v0,v1,v3], [v0,v2,v3]]\n */\nexport function splitQuadrilateral(vertices) {\n const [v0, v1, v2, v3] = vertices;\n // Vertices order:\n // 1 --- 3\n // | |\n // 0 --- 2\n return [\n [v0, v1, v3],\n [v0, v2, v3],\n ];\n}\n\n/**\n * Function that finds the list of adjacent elements for each node in the mesh\n * @param {object} meshData - Object containing nodal numbering (NOP)\n * @returns {object} Object containing:\n * - nodeNeighbors: Indices of neighboring elements per node\n * - neighborCount: Total number of neighboring elements per node\n */\nexport function computeNodeNeighbors(meshData) {\n const { nop, nodesXCoordinates } = meshData;\n const totalNodes = nodesXCoordinates.length;\n const nodesPerElement = nop[0].length;\n\n // Initialize arrays\n const nodeNeighbors = Array.from({ length: totalNodes }, () => []);\n const neighborCount = Array(totalNodes).fill(0);\n\n // Loop through all elements\n for (let elemIndex = 0; elemIndex < nop.length; elemIndex++) {\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) {\n const nodeIndex = nop[elemIndex][localNodeIndex] - 1;\n\n // Increment the total number of neighboring elements for this node\n neighborCount[nodeIndex] = neighborCount[nodeIndex] + 1;\n\n // Store the element index as a neighbor of this node\n nodeNeighbors[nodeIndex].push(elemIndex);\n }\n }\n\n return { nodeNeighbors, neighborCount };\n}\n\n/**\n * Function to extracts boundary line segments for ray casting\n * @param {object} meshData - Object containing mesh data\n * @returns {array} Array of segments\n */\nexport function getBoundarySegments(meshData) {\n let boundaryLineElements = [];\n let boundaryNodesSegments = [];\n let boundaryGlobalElementIndex = 0;\n let boundarySides;\n const { nodesXCoordinates, nodesYCoordinates, nop, boundaryElements, meshDimension, elementOrder } =\n meshData;\n\n if (meshDimension === \"1D\") {\n if (elementOrder === \"linear\") {\n 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 } else if (elementOrder === \"quadratic\") {\n 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 } else if (meshDimension === \"2D\") {\n if (elementOrder === \"linear\") {\n 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 } else if (elementOrder === \"quadratic\") {\n 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 }\n\n // Iterate over all boundaries\n for (let boundaryIndex = 0; boundaryIndex < boundaryElements.length; boundaryIndex++) {\n // Iterate over all elements in the current boundary\n for (\n let boundaryLocalElementIndex = 0;\n boundaryLocalElementIndex < boundaryElements[boundaryIndex].length;\n boundaryLocalElementIndex++\n ) {\n boundaryLineElements[boundaryGlobalElementIndex] =\n boundaryElements[boundaryIndex][boundaryLocalElementIndex];\n boundaryGlobalElementIndex++;\n // Retrieve the element index and the side\n const [elementIndex, side] = boundaryElements[boundaryIndex][boundaryLocalElementIndex];\n let boundaryLocalNodeIndices = boundarySides[side];\n let currentElementNodesX = [];\n let currentElementNodesY = [];\n\n for (\n let boundaryLocalNodeIndex = 0;\n boundaryLocalNodeIndex < boundaryLocalNodeIndices.length;\n boundaryLocalNodeIndex++\n ) {\n const globalNodeIndex = nop[elementIndex][boundaryLocalNodeIndices[boundaryLocalNodeIndex]] - 1;\n\n currentElementNodesX.push(nodesXCoordinates[globalNodeIndex]);\n currentElementNodesY.push(nodesYCoordinates[globalNodeIndex]);\n }\n\n // Create segments for this element\n for (let k = 0; k < currentElementNodesX.length - 1; k++) {\n boundaryNodesSegments.push([\n [currentElementNodesX[k], currentElementNodesY[k]],\n [currentElementNodesX[k + 1], currentElementNodesY[k + 1]],\n ]);\n }\n }\n }\n return boundaryNodesSegments;\n}\n","/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 1: [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 nodesPerElement = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < nodesPerElement; 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 nodesPerElement = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < nodesPerElement; 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 nodesPerElement = this.nop[elementIndex].length;\n const localJacobianMatrix = Array(nodesPerElement)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n const localResidualVector = Array(nodesPerElement).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 ([boundaryElementIndex, _]) => boundaryElementIndex === 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 < nodesPerElement; 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 nodesPerElement = this.nop[elementIndex].length;\n for (let nodeIndex = 0; nodeIndex < nodesPerElement; 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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 nodesPerElement,\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 < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector is zero for this case\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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, nodesPerElement } = FEAData;\n const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData;\n\n // Initialize local Jacobian matrix and local residual vector\n const localJacobianMatrix = Array(nodesPerElement)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n const localResidualVector = Array(nodesPerElement).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(nodesPerElement);\n const localToGlobalMap = Array(nodesPerElement);\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; 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 nodesPerElement,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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 nodesPerElement,\n });\n\n // Computation of Galerkin's residuals and local Jacobian matrix\n for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) {\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 1: [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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 nodesPerElement,\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 < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; 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 < nodesPerElement; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; 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 < nodesPerElement; 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 < nodesPerElement; 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, nodesPerElement } = 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(nodesPerElement)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n const localResidualVector = Array(nodesPerElement).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(nodesPerElement);\n const localToGlobalMap = Array(nodesPerElement);\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; 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 nodesPerElement,\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 < nodesPerElement; 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 < nodesPerElement; localNodeIndex1++) {\n let localToGlobalMap1 = localToGlobalMap[localNodeIndex1];\n // residualVector\n // TODO residualVector calculation here\n\n for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; 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 nodesPerElement,\n });\n\n // Calculate solution derivatives\n let solutionDerivX = 0;\n let solutionDerivY = 0;\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; 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 < nodesPerElement; 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 < nodesPerElement; 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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { initializeFEA } from \"../mesh/meshUtilsScript.js\";\nimport { assembleHeatConductionFront } from \"../models/heatConductionScript.js\";\nimport { ThermalBoundaryConditions } from \"../models/thermalBoundaryConditionsScript.js\";\nimport { assembleFrontPropagationFront } from \"../models/frontPropagationScript.js\";\nimport { GenericBoundaryConditions } from \"../models/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 nodesPerElement = FEAData.nodesPerElement;\n\n // Calculate required array sizes\n initializeFrontalArrays(nodesPerElement, 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.nodesPerElement; 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.nodesPerElement;\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} nodesPerElement - Number of nodes per element\n * @param {number} numElements - Number of elements in the mesh\n */\nfunction initializeFrontalArrays(nodesPerElement, numElements) {\n // Use the actual number of elements from the mesh\n frontalData.nodalNumbering = Array(numElements)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n frontalData.nodeConstraintCode = Array(nodesPerElement).fill(0);\n frontalData.boundaryValues = Array(nodesPerElement).fill(0);\n frontalData.globalResidualVector = Array(nodesPerElement).fill(0);\n frontalData.solutionVector = Array(nodesPerElement).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 = nodesPerElement;\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(nodesPerElement, 2000);\n frontalState.globalSolutionVector = Array(systemSize).fill(0);\n frontalState.frontDataIndex = 0;\n\n // Initialize elementData arrays\n elementData.localJacobianMatrix = Array(nodesPerElement)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n elementData.currentElementIndex = 0;\n\n // Initialize frontStorage arrays\n const frontSize = estimateFrontSize(nodesPerElement, 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} nodesPerElement - 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(nodesPerElement, numElements) {\n const frontWidthEstimate = Math.max(Math.ceil(Math.sqrt(numElements)) * nodesPerElement, nodesPerElement * 2);\n return frontWidthEstimate * numElements;\n}\n// Old function to estimate the required front size\n// function estimateFrontSize(nodesPerElement, numElements, nodesPerElement) {\n// const frontWidthEstimate = Math.ceil(Math.sqrt(numElements) * nodesPerElement * 2);\n// const frontSize = frontWidthEstimate * nodesPerElement * 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.nodesPerElement)\n .fill()\n .map(() => Array(FEAData.nodesPerElement).fill(0));\n let boundaryResidualVector = Array(FEAData.nodesPerElement).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(([boundaryElementIndex, _]) => boundaryElementIndex === 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.nodesPerElement; localNodeI++) {\n for (let localNodeJ = 0; localNodeJ < FEAData.nodesPerElement; 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.nodesPerElement; 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 nodesPerElement = meshData.nodesXCoordinates.length;\n const systemSize = Math.max(nodesPerElement, frontalState.globalSolutionVector.length);\n let localDestination = Array(FEAData.nodesPerElement).fill(0);\n let rowDestination = Array(FEAData.nodesPerElement).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(nodesPerElement).fill(0);\n let columnSwapCount = Array(nodesPerElement).fill(0);\n let lastAppearanceCheck = Array(nodesPerElement).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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 \"../models/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 * @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 = {}) {\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 // Extract context\n const { maxIterations = 100, tolerance = 1e-4 } = context;\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport {\n prepareMesh,\n pointInsideTriangle,\n pointInsideQuadrilateral,\n computeNodeNeighbors,\n getBoundarySegments,\n} from \"../mesh/meshUtilsScript.js\";\nimport { BasisFunctions } from \"../mesh/basisFunctionsScript.js\";\nimport { initializeFEA } from \"../mesh/meshUtilsScript.js\";\nimport { basicLog, debugLog, errorLog } from \"../utilities/loggingScript.js\";\n\n/**\n * Function to create plots of the solution vector\n * @param {object} result - Object containing solution vector and mesh information\n * @param {object} model - Object containing model properties\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n */\nexport function plotSolution(model, result, plotType, plotDivId) {\n const { nodesXCoordinates, nodesYCoordinates } = result.nodesCoordinates;\n const solutionVector = result.solutionVector;\n const solverConfig = model.solverConfig;\n const meshDimension = model.meshConfig.meshDimension;\n const meshData = prepareMesh(model.meshConfig); // Retrieve mesh connectivity details (used in splitQuadrilateral)\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: nodesXCoordinates,\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 plotWidth = Math.min(maxWindowWidth, 600);\n let plotHeight = 300;\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: 50, r: 50, t: 50, b: 50 },\n };\n\n Plotly.newPlot(plotDivId, [lineData], layout, { responsive: true });\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n // Check if solutionVector is a nested array\n let zData;\n if (Array.isArray(solutionVector[0])) {\n zData = solutionVector.map((val) => val[0]);\n } else {\n zData = solutionVector;\n }\n\n // Plot sizing parameters\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;\n\n // 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 // Create the plot\n let contourData = {\n x: nodesXCoordinates,\n y: nodesYCoordinates,\n z: zData,\n type: \"contour\",\n line: {\n smoothing: 0.85,\n },\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 Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n}\n\n/**\n * Function to generate a dense visualization grid and interpolate the FEM solution on it\n * @param {object} result - Object containing solution vector and mesh information\n * @param {object} model - Object containing model properties\n * @param {string} plotType - The type of plot\n * @param {string} plotDivId - The id of the div where the plot will be rendered\n */\nexport function plotInterpolatedSolution(model, result, plotType, plotDivId) {\n const { nodesXCoordinates, nodesYCoordinates } = result.nodesCoordinates; // TODO: Check if we should place it inside the 2D block\n const meshDimension = model.meshConfig.meshDimension;\n const meshData = prepareMesh(model.meshConfig); // Retrieve mesh connectivity details\n\n // Initialize BasisFunctions once here to avoid creating it inside the loop\n const basisFunctions = new BasisFunctions({\n meshDimension: model.meshConfig.meshDimension,\n elementOrder: model.meshConfig.elementOrder,\n });\n\n if (meshDimension === \"1D\" && plotType === \"line\") {\n // 1D plot region\n } else if (meshDimension === \"2D\" && plotType === \"contour\") {\n const visNodeXCoordinates = [];\n const visNodeYCoordinates = [];\n let visSolution = [];\n const visNodesX = 1e2; // Number of nodes along the x-axis of the visualization grid\n const visNodesY = 1e2; // Number of nodes along the y-axis of the visualization grid\n\n // const { nodesXCoordinates, nodesYCoordinates } = result.nodesCoordinates;\n const deltavisX = (Math.max(...nodesXCoordinates) - Math.min(...nodesXCoordinates)) / (visNodesX - 1);\n const deltavisY = (Math.max(...nodesYCoordinates) - Math.min(...nodesYCoordinates)) / (visNodesY - 1);\n\n visNodeXCoordinates[0] = Math.min(...nodesXCoordinates);\n visNodeYCoordinates[0] = Math.min(...nodesYCoordinates);\n\n for (let visNodeIndexY = 1; visNodeIndexY < visNodesY; visNodeIndexY++) {\n visNodeXCoordinates[visNodeIndexY] = visNodeXCoordinates[0];\n visNodeYCoordinates[visNodeIndexY] = visNodeYCoordinates[0] + visNodeIndexY * deltavisY;\n }\n\n for (let visNodeIndexX = 1; visNodeIndexX < visNodesX; visNodeIndexX++) {\n const nnode = visNodeIndexX * visNodesY;\n visNodeXCoordinates[nnode] = visNodeXCoordinates[0] + visNodeIndexX * deltavisX;\n visNodeYCoordinates[nnode] = visNodeYCoordinates[0];\n\n for (let visNodeIndexY = 1; visNodeIndexY < visNodesY; visNodeIndexY++) {\n visNodeXCoordinates[nnode + visNodeIndexY] = visNodeXCoordinates[nnode];\n visNodeYCoordinates[nnode + visNodeIndexY] = visNodeYCoordinates[nnode] + visNodeIndexY * deltavisY;\n }\n }\n\n const visNodeCoordinates = { visNodeXCoordinates, visNodeYCoordinates };\n\n // Initialize visSolution with null for all visualization nodes\n visSolution = new Array(visNodesX * visNodesY).fill(null);\n\n // Get boundary segments for ray casting\n const boundarySegments = getBoundarySegments(meshData);\n\n // Perform adjacency-based search to find which element contains a given point (quick search)\n const { nodeNeighbors, neighborCount } = computeNodeNeighbors(meshData);\n let lastParentElement = 0;\n for (let visNodeIndex = 0; visNodeIndex < visNodesX * visNodesY; visNodeIndex++) {\n // Ray casting check\n if (\n !pointInsidePolygon(\n visNodeXCoordinates[visNodeIndex],\n visNodeYCoordinates[visNodeIndex],\n boundarySegments\n )\n ) {\n continue;\n }\n let found = false;\n for (\n let localNodeIndex = 0;\n localNodeIndex < meshData.nop[lastParentElement].length;\n localNodeIndex++\n ) {\n let globalNodeIndex = meshData.nop[lastParentElement][localNodeIndex] - 1;\n for (\n let neighborElementsIndex = 0;\n neighborElementsIndex < neighborCount[globalNodeIndex];\n neighborElementsIndex++\n ) {\n let currentElement = nodeNeighbors[globalNodeIndex][neighborElementsIndex];\n const searchResult = pointSearch(\n model,\n meshData,\n result,\n currentElement,\n visNodeXCoordinates[visNodeIndex],\n visNodeYCoordinates[visNodeIndex],\n basisFunctions\n );\n\n if (searchResult.inside) {\n lastParentElement = currentElement;\n visSolution[visNodeIndex] = searchResult.value;\n found = true;\n break;\n }\n }\n if (found) break;\n }\n\n // Scan all elements to find which element contains a given point (slow search)\n if (!found) {\n for (let currentElement = 0; currentElement < meshData.nop.length; currentElement++) {\n const searchResult = pointSearch(\n model,\n meshData,\n result,\n currentElement,\n visNodeXCoordinates[visNodeIndex],\n visNodeYCoordinates[visNodeIndex],\n basisFunctions\n );\n\n if (searchResult.inside) {\n lastParentElement = currentElement;\n visSolution[visNodeIndex] = searchResult.value;\n found = true;\n break;\n }\n }\n }\n }\n\n // Plot sizing parameters\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;\n\n // Layout properties\n let layout = {\n title: `${plotType} plot (interpolated) - ${model.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 // Create the plot\n let contourData = {\n x: visNodeXCoordinates,\n y: visNodeYCoordinates,\n z: visSolution,\n type: \"contour\",\n line: {\n smoothing: 0.85,\n },\n contours: {\n coloring: \"heatmap\",\n showlabels: false,\n },\n //colorscale: 'Viridis',\n colorbar: {\n title: \"Solution\",\n },\n name: \"Interpolated Solution Field\",\n };\n\n Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true });\n }\n}\n\n/**\n * Function to search if a point is inside an element and interpolate the solution\n * @param {object} model - Object containing model properties\n * @param {object} meshData - Object containing mesh data\n * @param {object} result - Object containing solution vector and mesh information\n * @param {number} currentElement - Index of the element to check\n * @param {number} visNodeXCoordinate - X-coordinate of the point\n * @param {number} visNodeYCoordinate - Y-coordinate of the point\n * @param {object} basisFunctions - Instance of BasisFunctions class\n * @returns {object} Object containing inside boolean and interpolated value\n */\nfunction pointSearch(model, meshData, result, currentElement, visNodeXCoordinate, visNodeYCoordinate, basisFunctions) {\n const { nodesXCoordinates, nodesYCoordinates } = result.nodesCoordinates;\n const nodesPerElement = meshData.nop[currentElement].length;\n\n if (nodesPerElement === 4) {\n // Linear quadrilateral element\n let vertices = [\n [\n nodesXCoordinates[meshData.nop[currentElement][0] - 1],\n nodesYCoordinates[meshData.nop[currentElement][0] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][1] - 1],\n nodesYCoordinates[meshData.nop[currentElement][1] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][2] - 1],\n nodesYCoordinates[meshData.nop[currentElement][2] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][3] - 1],\n nodesYCoordinates[meshData.nop[currentElement][3] - 1],\n ],\n ];\n const pointCheck = pointInsideQuadrilateral(visNodeXCoordinate, visNodeYCoordinate, vertices);\n if (pointCheck.inside) {\n return {\n inside: true,\n value: solutionInterpolation(model, meshData, result, currentElement, pointCheck.ksi, pointCheck.eta, basisFunctions),\n };\n }\n } else if (nodesPerElement === 9) {\n // Quadratic quadrilateral element\n let vertices = [\n [\n nodesXCoordinates[meshData.nop[currentElement][0] - 1],\n nodesYCoordinates[meshData.nop[currentElement][0] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][2] - 1],\n nodesYCoordinates[meshData.nop[currentElement][2] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][6] - 1],\n nodesYCoordinates[meshData.nop[currentElement][6] - 1],\n ],\n [\n nodesXCoordinates[meshData.nop[currentElement][8] - 1],\n nodesYCoordinates[meshData.nop[currentElement][8] - 1],\n ],\n ];\n const pointCheck = pointInsideQuadrilateral(visNodeXCoordinate, visNodeYCoordinate, vertices);\n if (pointCheck.inside) {\n return {\n inside: true,\n value: solutionInterpolation(model, meshData, result, currentElement, pointCheck.ksi, pointCheck.eta, basisFunctions),\n };\n }\n } // TODO: Add also triangular element cases\n return { inside: false, value: null };\n}\n\n/**\n * Function to interpolate the solution at a specific point (ksi, eta) within an element\n * @param {object} model - Object containing model properties\n * @param {object} meshData - Object containing mesh data\n * @param {object} result - Object containing solution vector and mesh information\n * @param {number} elementIndex - Index of the element containing the point\n * @param {number} ksi - First natural coordinate (ksi)\n * @param {number} eta - Second natural coordinate (eta)\n * @param {object} basisFunctions - Instance of BasisFunctions class\n * @returns {number} Interpolated solution value\n */\nfunction solutionInterpolation(model, meshData, result, elementIndex, ksi, eta, basisFunctions) {\n // Initialize FEA components\n const solutionVector = result.solutionVector;\n const nodesPerElement = meshData.nop[elementIndex].length;\n\n // Get basis functions for the current point\n const basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(ksi, eta);\n let basisFunction = basisFunctionsAndDerivatives.basisFunction;\n\n // Check if solutionVector is a nested array\n let zData;\n if (Array.isArray(solutionVector[0])) {\n zData = solutionVector.map((val) => val[0]);\n } else {\n zData = solutionVector;\n }\n\n // Interpolate solution\n let solutionInterpolationValue = 0;\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) {\n solutionInterpolationValue +=\n zData[meshData.nop[elementIndex][localNodeIndex] - 1] * basisFunction[localNodeIndex];\n }\n\n return solutionInterpolationValue;\n}\n\n/**\n * Function to check if a point is inside a polygon using ray casting algorithm\n * @param {number} x - X-coordinate of the point\n * @param {number} y - Y-coordinate of the point\n * @param {array} segments - Array of boundary segments\n * @returns {boolean} True if the point is inside the polygon\n */\nfunction pointInsidePolygon(x, y, segments) {\n let inside = false;\n for (let i = 0; i < segments.length; i++) {\n const [[x1, y1], [x2, y2]] = segments[i];\n const intersect = y1 > y !== y2 > y && x < ((x2 - x1) * (y - y1)) / (y2 - y1) + x1;\n if (intersect) inside = !inside;\n }\n return inside;\n}\n","/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\n// Internal imports\nimport { newtonRaphson } from \"./methods/newtonRaphsonScript.js\";\nimport { solveLinearSystem } from \"./methods/linearSystemSolverScript.js\";\nimport { solveLinearSystemAsync } from \"./methods/linearSystemSolverScript.js\";\nimport { prepareMesh } from \"./mesh/meshUtilsScript.js\";\nimport { assembleFrontPropagationMat } from \"./models/frontPropagationScript.js\";\nimport { assembleGeneralFormPDEMat, assembleGeneralFormPDEFront } from \"./models/generalFormPDEScript.js\";\nimport { assembleHeatConductionMat, assembleHeatConductionFront } from \"./models/heatConductionScript.js\";\nimport { runFrontalSolver } from \"./methods/frontalSolverScript.js\";\nimport { basicLog, debugLog, warnLog, 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 containifng the solution vector and 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 warnLog(\n \"FEAScript is provided “as is” without any warranty. The authors are not responsible for any damages or losses that may result from using the software. See the license for more details: https://github.com/FEAScript/FEAScript-core/blob/main/LICENSE\"\n );\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?.coefficientFunctions) {\n this.coefficientFunctions = options.coefficientFunctions;\n debugLog(\"Coefficient functions set\");\n }\n // Only update if a value is provided, otherwise keep the default\n if (options?.maxIterations !== undefined) {\n this.maxIterations = options.maxIterations;\n }\n if (options?.tolerance !== undefined) {\n this.tolerance = options.tolerance;\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 /**\n * Function to solve the finite element problem synchronously\n * @param {object} [options] - Additional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {object} An object containing the solution vector and mesh information\n */\n solve(options = {}) {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n errorLog(\"Solver config, mesh config, and boundary conditions must be set before solving.\");\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 and nodal numbering 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 basicLog(`Using solver: ${this.solverConfig}`);\n if (this.solverConfig === \"heatConductionScript\") {\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 maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n });\n solutionVector = linearSystemResult.solutionVector;\n }\n } else if (this.solverConfig === \"frontPropagationScript\") {\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 // TODO: Consider using different maxIterations/tolerance for Newton-Raphson and linear solver\n maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\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);\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 // 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 maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n });\n solutionVector = linearSystemResult.solutionVector;\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n\n /**\n * Function to solve the finite element problem asynchronously\n * @param {object} computeEngine - The compute engine to use for the asynchronous solver (e.g., a worker or a WebGPU context)\n * @param {object} [options] - Additional parameters for the solver, such as `maxIterations` and `tolerance`\n * @returns {Promise} A promise that resolves to an object containing the solution vector and the coordinates of the mesh nodes\n */\n async solveAsync(computeEngine, options = {}) {\n if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) {\n errorLog(\"Solver config, mesh config, and boundary conditions must be set before solving.\");\n }\n\n let jacobianMatrix = [];\n let residualVector = [];\n let solutionVector = [];\n\n basicLog(\"Preparing mesh...\");\n const meshData = prepareMesh(this.meshConfig);\n basicLog(\"Mesh preparation completed\");\n const nodesCoordinates = {\n nodesXCoordinates: meshData.nodesXCoordinates,\n nodesYCoordinates: meshData.nodesYCoordinates,\n };\n\n basicLog(\"Beginning solving process...\");\n console.time(\"totalSolvingTime\");\n\n basicLog(`Using solver: ${this.solverConfig}`);\n if (this.solverConfig === \"heatConductionScript\") {\n ({ jacobianMatrix, residualVector } = assembleHeatConductionMat(meshData, this.boundaryConditions));\n\n if (this.solverMethod === \"jacobi-gpu\") {\n const { solutionVector: x } = await solveLinearSystemAsync(\n \"jacobi-gpu\",\n jacobianMatrix,\n residualVector,\n {\n computeEngine,\n maxIterations: options.maxIterations ?? this.maxIterations,\n tolerance: options.tolerance ?? this.tolerance,\n }\n );\n solutionVector = x;\n } else {\n // Other async solver\n }\n }\n console.timeEnd(\"totalSolvingTime\");\n basicLog(\"Solving process completed\");\n\n return { solutionVector, nodesCoordinates };\n }\n}\n","/**\n * ════════════════════════════════════════════════════════════════\n * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 nodesPerElement,\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 < nodesPerElement; 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 nodesPerElement,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < nodesPerElement; 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 < nodesPerElement; 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 < nodesPerElement; 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, nodesPerElement } = 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(nodesPerElement)\n .fill()\n .map(() => Array(nodesPerElement).fill(0));\n const localResidualVector = Array(nodesPerElement).fill(0);\n\n // Build the mapping from local node indices to global node indices\n const ngl = Array(nodesPerElement);\n const localToGlobalMap = Array(nodesPerElement);\n for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; 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 nodesPerElement,\n });\n\n // Calculate the physical coordinate for this Gauss point\n let xCoord = 0;\n for (let i = 0; i < nodesPerElement; 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 < nodesPerElement; 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 < nodesPerElement; 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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\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 * FEAScript Core Library\n * Lightweight Finite Element Simulation in JavaScript\n * Version: 0.2.0 (RC) | https://feascript.com\n * MIT License © 2023–2025 FEAScript\n * ════════════════════════════════════════════════════════════════\n */\n\nexport { FEAScriptModel } from \"./FEAScript.js\";\nexport { importGmshQuadTri } from \"./readers/gmshReaderScript.js\"; //TODO rename importGmshQuadTri to importGmsh\nexport { logSystem } from \"./utilities/loggingScript.js\";\nexport { plotSolution, plotInterpolatedSolution } from \"./visualization/plotSolutionScript.js\";\nexport { FEAScriptWorker } from \"./workers/workerScript.js\";\nexport const printVersion = \"0.2.0 (RC)\";"],"names":["euclideanNorm","vector","norm","i","length","Math","sqrt","currentLogLevel","debugLog","message","console","log","basicLog","errorLog","proxyMarker","Symbol","createEndpoint","releaseProxy","finalizer","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","wrap","value","serialized","Error","isError","name","stack","Object","assign","ep","globalThis","allowedOrigins","addEventListener","callback","ev","data","origin","allowedOrigin","RegExp","test","isAllowedOrigin","warn","id","type","path","argumentList","map","fromWireValue","returnValue","parent","slice","reduce","prop","rawValue","apply","proxy","transfers","transferCache","set","transfer","undefined","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","error","TypeError","endpoint","constructor","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","Array","prototype","concat","handler","serializedValue","msg","fill","floor","random","Number","MAX_SAFE_INTEGER","join","solveLinearSystem","solverMethod","jacobianMatrix","residualVector","options","maxIterations","tolerance","solutionVector","converged","iterations","time","jacobianMatrixSparse","math","sparse","luFactorization","slu","solutionMatrix","lusolve","squeeze","valueOf","jacobiSolverResult","A","b","x0","n","x","xNew","iter","sum","j","maxDiff","max","abs","jacobiSolver","timeEnd","async","solveLinearSystemAsync","isArray","toArray","created","computeEngine","worker","Worker","URL","document","location","require","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","Comlink.wrap","initialize","createDefaultComputeEngine","result","webgpuJacobiSolver","destroy","terminate","BasisFunctions","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","quadElements","triangleElements","JSON","stringify","elementTypes","mappedNodalNumbering","elementIndex","gmshNodes","FEAScriptNodes","push","physicalPropMap","boundaryElements","fixedBoundaryElements","boundaryNodePairs","forEach","dimension","tag","nodesPair","node1","node2","foundElement","elementConnectivity","includes","side","node1Index","indexOf","node2Index","Mesh1D","super","generateMesh","nodesXCoordinates","totalNodesX","deltaX","nodeIndex","generateNodalNumbering1D","findBoundaryElements","nop","columnCounter","sideIndex","Mesh2D","nodesYCoordinates","totalNodesY","deltaY","nodeIndexY","nodeIndexX","nnode","generateNodalNumbering2D","rowCounter","elementIndexX","elementIndexY","nodeIndex1","nodeIndex2","NumericalIntegration","getGaussPointsAndWeights","gaussPoints","gaussWeights","prepareMesh","meshConfig","mesh","nodesCoordinatesAndNumbering","totalElements","totalNodes","initializeFEA","meshData","colIndex","basisFunctions","gaussPointsAndWeights","localToGlobalMap","nodesPerElement","performIsoparametricMapping1D","params","xCoordinates","ksiDerivX","localNodeIndex","detJacobian","basisFunctionDerivX","performIsoparametricMapping2D","yCoordinates","etaDerivX","ksiDerivY","etaDerivY","basisFunctionDerivY","pointInsideTriangle","y","vertices","v0","v1","v2","denom","inside","pointInsideQuadrilateral","firstTriangleVertices","secondTriangleVertices","v3","splitQuadrilateral","pointInsideFirstTriangle","pointInsideSecondTriangle","getDistanceFromLine","p1","p2","distLeft","distRight","distBottom","ThermalBoundaryConditions","boundaryConditions","imposeConstantTempBoundaryConditions","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","localResidualVector","boundaryElement","find","boundaryElementIndex","_","assembleHeatConductionMat","FEAData","gaussPointIndex1","mappingResult","localNodeIndex1","localToGlobalMap1","localToGlobalMap2","gaussPointIndex2","thermalBoundaryConditions","assembleHeatConductionFront","ngl","globalIndex","GenericBoundaryConditions","imposeDirichletBoundaryConditions","imposeConstantValueBoundaryConditionsFront","assembleFrontPropagationMat","eikonalActivationFlag","eikonalViscousTerm","solutionDerivX","solutionDerivY","assembleFrontPropagationFront","frontalData","frontalState","elementData","currentElementIndex","frontStorage","runFrontalSolver","assembleFront","numElements","globalResidualVector","topologyData","lateralData","writeFlag","transformationFlag","determinant","systemSize","globalSolutionVector","frontDataIndex","frontSize","frontWidthEstimate","ceil","estimateFrontSize","frontValues","columnHeaders","pivotRow","pivotData","initializeFrontalArrays","dirichletBoundaryConditionsHandler","currentSolutionVector","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","nodesCoordinates","boundaryLocalJacobianMatrix","boundaryResidualVector","isOnRobinTypeBoundary","some","localNodeI","localNodeJ","iterationIndex","accumulatedValue","newtonRaphson","assembleMat","context","errorNorm","initialSolution","pointSearch","model","visNodeXCoordinate","visNodeYCoordinate","pointCheck","solutionInterpolation","zData","solutionInterpolationValue","pointInsidePolygon","segments","x1","y1","x2","y2","solverConfig","coefficientFunctions","setSolverConfig","setMeshConfig","addBoundaryCondition","condition","setSolverMethod","solve","eikonalExteralIterations","newtonRaphsonResult","B","C","D","xCoord","a","d","globalNodeIndex1","assembleGeneralFormPDEMat","solveAsync","feaWorker","isReady","_initWorker","onerror","event","workerWrapper","_ensureReady","reject","attempts","checkReady","setTimeout","startTime","performance","now","toFixed","getModelInfo","ping","file","gmshV","ascii","fltBytes","lines","text","split","line","trim","filter","section","lineIndex","nodeEntityBlocks","nodeBlocksProcessed","currentNodeBlock","numNodes","nodeTagsCollected","nodeTags","nodeCoordinatesCollected","elementEntityBlocks","elementBlocksProcessed","currentElementBlock","dim","elementType","elementsProcessedInBlock","boundaryElementsByTag","parts","part","parseFloat","parseInt","replace","parametric","nodeTag","nodeIndices","idx","physicalTag","boundaryNodes","nodes","level","plotType","plotDivId","visNodeXCoordinates","visNodeYCoordinates","visSolution","visNodesX","visNodesY","deltavisX","min","deltavisY","visNodeIndexY","visNodeIndexX","boundarySegments","boundarySides","boundaryLineElements","boundaryNodesSegments","boundaryGlobalElementIndex","boundaryIndex","boundaryLocalElementIndex","boundaryLocalNodeIndices","currentElementNodesX","currentElementNodesY","boundaryLocalNodeIndex","k","getBoundarySegments","nodeNeighbors","neighborCount","from","elemIndex","computeNodeNeighbors","lastParentElement","visNodeIndex","found","neighborElementsIndex","searchResult","maxWindowWidth","window","innerWidth","aspectRatio","plotWidth","plotHeight","layout","title","width","height","xaxis","yaxis","margin","l","t","hovermode","contourData","z","smoothing","contours","coloring","showlabels","colorbar","Plotly","newPlot","responsive","yData","lineData","mode","color"],"mappings":"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"} diff --git a/examples/frontPropagationScript/solidificationFront2D/solidificationFront2D.js b/examples/frontPropagationScript/solidificationFront2D/solidificationFront2D.js index 80841ce..48e7743 100644 --- a/examples/frontPropagationScript/solidificationFront2D/solidificationFront2D.js +++ b/examples/frontPropagationScript/solidificationFront2D/solidificationFront2D.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Import Math.js diff --git a/examples/generalFormPDEScript/advectionDiffusion1D/advectionDiffusion1D.js b/examples/generalFormPDEScript/advectionDiffusion1D/advectionDiffusion1D.js index 640935f..311ed42 100644 --- a/examples/generalFormPDEScript/advectionDiffusion1D/advectionDiffusion1D.js +++ b/examples/generalFormPDEScript/advectionDiffusion1D/advectionDiffusion1D.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Import Math.js diff --git a/examples/heatConductionScript/heatConduction1DWall/heatConduction1DWall.js b/examples/heatConductionScript/heatConduction1DWall/heatConduction1DWall.js index f01f541..a927278 100644 --- a/examples/heatConductionScript/heatConduction1DWall/heatConduction1DWall.js +++ b/examples/heatConductionScript/heatConduction1DWall/heatConduction1DWall.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Import Math.js diff --git a/examples/heatConductionScript/heatConduction2DFin/heatConduction2DFin.js b/examples/heatConductionScript/heatConduction2DFin/heatConduction2DFin.js index 50dc216..ae3e75a 100644 --- a/examples/heatConductionScript/heatConduction2DFin/heatConduction2DFin.js +++ b/examples/heatConductionScript/heatConduction2DFin/heatConduction2DFin.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Import Math.js diff --git a/examples/heatConductionScript/heatConduction2DFin/heatConduction2DFinGmsh.js b/examples/heatConductionScript/heatConduction2DFin/heatConduction2DFinGmsh.js index 9ba4757..f4d657c 100644 --- a/examples/heatConductionScript/heatConduction2DFin/heatConduction2DFinGmsh.js +++ b/examples/heatConductionScript/heatConduction2DFin/heatConduction2DFinGmsh.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Import required Node.js modules diff --git a/package-lock.json b/package-lock.json index 29cf3e0..5573a54 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "feascript", - "version": "0.1.4", + "version": "0.2.0 (RC)", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/package.json b/package.json index c6ef70d..5bc16d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "feascript", - "version": "0.1.4", + "version": "0.2.0 (RC)", "description": "Lightweight finite element simulation library built in JavaScript for browser-based physics and engineering simulations", "main": "dist/feascript.cjs.js", "module": "dist/feascript.esm.js", diff --git a/src/FEAScript.js b/src/FEAScript.js index cf7d2f4..e9b8e79 100644 --- a/src/FEAScript.js +++ b/src/FEAScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Internal imports @@ -22,7 +23,7 @@ import { basicLog, debugLog, warnLog, errorLog } from "./utilities/loggingScript * @param {string} solverConfig - Parameter specifying the type of solver * @param {object} meshConfig - Object containing computational mesh details * @param {object} boundaryConditions - Object containing boundary conditions for the finite element analysis - * @returns {object} An object containifng the solution vector and additional mesh information + * @returns {object} An object containifng the solution vector and mesh information */ export class FEAScriptModel { constructor() { @@ -79,7 +80,7 @@ export class FEAScriptModel { /** * Function to solve the finite element problem synchronously * @param {object} [options] - Additional parameters for the solver, such as `maxIterations` and `tolerance` - * @returns {object} An object containing the solution vector and the coordinates of the mesh nodes + * @returns {object} An object containing the solution vector and mesh information */ solve(options = {}) { if (!this.solverConfig || !this.meshConfig || !this.boundaryConditions) { @@ -105,7 +106,7 @@ export class FEAScriptModel { const meshData = prepareMesh(this.meshConfig); basicLog("Mesh preparation completed"); - // Extract node coordinates from meshData + // Extract node coordinates and nodal numbering from meshData const nodesCoordinates = { nodesXCoordinates: meshData.nodesXCoordinates, nodesYCoordinates: meshData.nodesYCoordinates, @@ -228,11 +229,16 @@ export class FEAScriptModel { ({ jacobianMatrix, residualVector } = assembleHeatConductionMat(meshData, this.boundaryConditions)); if (this.solverMethod === "jacobi-gpu") { - const { solutionVector: x } = await solveLinearSystemAsync("jacobi-gpu", jacobianMatrix, residualVector, { - computeEngine, - maxIterations: options.maxIterations ?? this.maxIterations, - tolerance: options.tolerance ?? this.tolerance, - }); + const { solutionVector: x } = await solveLinearSystemAsync( + "jacobi-gpu", + jacobianMatrix, + residualVector, + { + computeEngine, + maxIterations: options.maxIterations ?? this.maxIterations, + tolerance: options.tolerance ?? this.tolerance, + } + ); solutionVector = x; } else { // Other async solver @@ -243,5 +249,4 @@ export class FEAScriptModel { return { solutionVector, nodesCoordinates }; } - } diff --git a/src/index.js b/src/index.js index 81f6c62..10f1d48 100644 --- a/src/index.js +++ b/src/index.js @@ -1,14 +1,15 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ export { FEAScriptModel } from "./FEAScript.js"; -export { importGmshQuadTri } from "./readers/gmshReaderScript.js"; +export { importGmshQuadTri } from "./readers/gmshReaderScript.js"; //TODO rename importGmshQuadTri to importGmsh export { logSystem } from "./utilities/loggingScript.js"; -export { plotSolution } from "./visualization/plotSolutionScript.js"; +export { plotSolution, plotInterpolatedSolution } from "./visualization/plotSolutionScript.js"; export { FEAScriptWorker } from "./workers/workerScript.js"; -export const printVersion = "0.1.4"; \ No newline at end of file +export const printVersion = "0.2.0 (RC)"; \ No newline at end of file diff --git a/src/mesh/basisFunctionsScript.js b/src/mesh/basisFunctionsScript.js index 1c80073..abd80ba 100644 --- a/src/mesh/basisFunctionsScript.js +++ b/src/mesh/basisFunctionsScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Internal imports diff --git a/src/mesh/meshGenerationScript.js b/src/mesh/meshGenerationScript.js index d8f1358..ca29b2a 100644 --- a/src/mesh/meshGenerationScript.js +++ b/src/mesh/meshGenerationScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Internal imports @@ -50,13 +51,21 @@ export class Mesh { } /** - * Method to parse the mesh from the GMSH format to the FEAScript format + * Method to parse the mesh from the Gmsh format to the FEAScript format */ parseMeshFromGmsh() { if (!this.parsedMesh.nodalNumbering) { errorLog("No valid nodal numbering found in the parsed mesh."); } + // If this parsed mesh was already converted in a previous run, don't re-process it. + // Just mark this Mesh instance as ready so prepareMesh() doesn't fall back to generateMesh(). + if (Array.isArray(this.parsedMesh.nodalNumbering)) { + this.boundaryElementsProcessed = true; + this.parsedMesh.boundaryElementsProcessed = true; + return this.parsedMesh; + } + if ( typeof this.parsedMesh.nodalNumbering === "object" && !Array.isArray(this.parsedMesh.nodalNumbering) @@ -66,52 +75,52 @@ export class Mesh { const triangleElements = this.parsedMesh.nodalNumbering.triangleElements || []; debugLog( - "Initial parsed mesh nodal numbering from GMSH format: " + + "Initial parsed mesh nodal numbering from Gmsh format: " + JSON.stringify(this.parsedMesh.nodalNumbering) ); // Check if it has quadElements or triangleElements structure from gmshReader if (this.parsedMesh.elementTypes[3] || this.parsedMesh.elementTypes[10]) { - // Map nodal numbering from GMSH format to FEAScript format for quad elements + // Map nodal numbering from Gmsh format to FEAScript format for quad elements const mappedNodalNumbering = []; - for (let elemIdx = 0; elemIdx < quadElements.length; elemIdx++) { - const gmshNodes = quadElements[elemIdx]; - const feaScriptNodes = new Array(gmshNodes.length); + for (let elementIndex = 0; elementIndex < quadElements.length; elementIndex++) { + const gmshNodes = quadElements[elementIndex]; + const FEAScriptNodes = new Array(gmshNodes.length); // Check for element type based on number of nodes if (gmshNodes.length === 4) { // Simple mapping for linear quad elements (4 nodes) - // GMSH: FEAScript: + // Gmsh: FEAScript: // 3 --- 2 1 --- 3 // | | --> | | // 0 --- 1 0 --- 2 - feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0 - feaScriptNodes[1] = gmshNodes[3]; // 3 -> 1 - feaScriptNodes[2] = gmshNodes[1]; // 1 -> 2 - feaScriptNodes[3] = gmshNodes[2]; // 2 -> 3 + FEAScriptNodes[0] = gmshNodes[0]; // 0 -> 0 + FEAScriptNodes[1] = gmshNodes[3]; // 3 -> 1 + FEAScriptNodes[2] = gmshNodes[1]; // 1 -> 2 + FEAScriptNodes[3] = gmshNodes[2]; // 2 -> 3 } else if (gmshNodes.length === 9) { // Mapping for quadratic quad elements (9 nodes) - // GMSH: FEAScript: + // Gmsh: FEAScript: // 3--6--2 2--5--8 // | | | | // 7 8 5 --> 1 4 7 // | | | | // 0--4--1 0--3--6 - feaScriptNodes[0] = gmshNodes[0]; // 0 -> 0 - feaScriptNodes[1] = gmshNodes[7]; // 7 -> 1 - feaScriptNodes[2] = gmshNodes[3]; // 3 -> 2 - feaScriptNodes[3] = gmshNodes[4]; // 4 -> 3 - feaScriptNodes[4] = gmshNodes[8]; // 8 -> 4 - feaScriptNodes[5] = gmshNodes[6]; // 6 -> 5 - feaScriptNodes[6] = gmshNodes[1]; // 1 -> 6 - feaScriptNodes[7] = gmshNodes[5]; // 5 -> 7 - feaScriptNodes[8] = gmshNodes[2]; // 2 -> 8 + FEAScriptNodes[0] = gmshNodes[0]; // 0 -> 0 + FEAScriptNodes[1] = gmshNodes[7]; // 7 -> 1 + FEAScriptNodes[2] = gmshNodes[3]; // 3 -> 2 + FEAScriptNodes[3] = gmshNodes[4]; // 4 -> 3 + FEAScriptNodes[4] = gmshNodes[8]; // 8 -> 4 + FEAScriptNodes[5] = gmshNodes[6]; // 6 -> 5 + FEAScriptNodes[6] = gmshNodes[1]; // 1 -> 6 + FEAScriptNodes[7] = gmshNodes[5]; // 5 -> 7 + FEAScriptNodes[8] = gmshNodes[2]; // 2 -> 8 } - mappedNodalNumbering.push(feaScriptNodes); + mappedNodalNumbering.push(FEAScriptNodes); } this.parsedMesh.nodalNumbering = mappedNodalNumbering; @@ -120,7 +129,7 @@ export class Mesh { } debugLog( - "Nodal numbering after mapping from GMSH to FEAScript format: " + + "Nodal numbering after mapping from Gmsh to FEAScript format: " + JSON.stringify(this.parsedMesh.nodalNumbering) ); @@ -175,21 +184,25 @@ export class Mesh { let foundElement = false; // Loop through all elements in the mesh - for (let elemIdx = 0; elemIdx < this.parsedMesh.nodalNumbering.length; elemIdx++) { - const elemNodes = this.parsedMesh.nodalNumbering[elemIdx]; + for ( + let elementIndex = 0; + elementIndex < this.parsedMesh.nodalNumbering.length; + elementIndex++ + ) { + const elementConnectivity = this.parsedMesh.nodalNumbering[elementIndex]; // For linear quadrilateral linear elements (4 nodes) - if (elemNodes.length === 4) { + if (elementConnectivity.length === 4) { // Check if both boundary nodes are in this element - if (elemNodes.includes(node1) && elemNodes.includes(node2)) { + if (elementConnectivity.includes(node1) && elementConnectivity.includes(node2)) { // Find which side of the element these nodes form let side; - const node1Index = elemNodes.indexOf(node1); - const node2Index = elemNodes.indexOf(node2); + const node1Index = elementConnectivity.indexOf(node1); + const node2Index = elementConnectivity.indexOf(node2); debugLog( - ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join( + ` Found element ${elementIndex} containing boundary nodes. Element nodes: [${elementConnectivity.join( ", " )}]` ); @@ -207,47 +220,47 @@ export class Mesh { (node1Index === 2 && node2Index === 0) ) { side = 0; // Bottom side - debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`); + debugLog(` These nodes form the BOTTOM side (${side}) of element ${elementIndex}`); } else if ( (node1Index === 0 && node2Index === 1) || (node1Index === 1 && node2Index === 0) ) { side = 1; // Left side - debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`); + debugLog(` These nodes form the LEFT side (${side}) of element ${elementIndex}`); } else if ( (node1Index === 1 && node2Index === 3) || (node1Index === 3 && node2Index === 1) ) { side = 2; // Top side - debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`); + debugLog(` These nodes form the TOP side (${side}) of element ${elementIndex}`); } else if ( (node1Index === 2 && node2Index === 3) || (node1Index === 3 && node2Index === 2) ) { side = 3; // Right side - debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`); + debugLog(` These nodes form the RIGHT side (${side}) of element ${elementIndex}`); } // Add the element and side to the boundary elements array - this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]); + this.parsedMesh.boundaryElements[prop.tag].push([elementIndex, side]); debugLog( - ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}` + ` Added element-side pair [${elementIndex}, ${side}] to boundary tag ${prop.tag}` ); foundElement = true; break; } - } else if (elemNodes.length === 9) { + } else if (elementConnectivity.length === 9) { // For quadratic quadrilateral elements (9 nodes) // Check if both boundary nodes are in this element - if (elemNodes.includes(node1) && elemNodes.includes(node2)) { + if (elementConnectivity.includes(node1) && elementConnectivity.includes(node2)) { // Find which side of the element these nodes form let side; - const node1Index = elemNodes.indexOf(node1); - const node2Index = elemNodes.indexOf(node2); + const node1Index = elementConnectivity.indexOf(node1); + const node2Index = elementConnectivity.indexOf(node2); debugLog( - ` Found element ${elemIdx} containing boundary nodes. Element nodes: [${elemNodes.join( + ` Found element ${elementIndex} containing boundary nodes. Element nodes: [${elementConnectivity.join( ", " )}]` ); @@ -272,7 +285,7 @@ export class Mesh { (node1Index === 6 && node2Index === 3) ) { side = 0; // Bottom side (nodes 0, 3, 6) - debugLog(` These nodes form the BOTTOM side (${side}) of element ${elemIdx}`); + debugLog(` These nodes form the BOTTOM side (${side}) of element ${elementIndex}`); } else if ( (node1Index === 0 && node2Index === 2) || (node1Index === 2 && node2Index === 0) || @@ -282,7 +295,7 @@ export class Mesh { (node1Index === 2 && node2Index === 1) ) { side = 1; // Left side (nodes 0, 1, 2) - debugLog(` These nodes form the LEFT side (${side}) of element ${elemIdx}`); + debugLog(` These nodes form the LEFT side (${side}) of element ${elementIndex}`); } else if ( (node1Index === 2 && node2Index === 8) || (node1Index === 8 && node2Index === 2) || @@ -292,7 +305,7 @@ export class Mesh { (node1Index === 8 && node2Index === 5) ) { side = 2; // Top side (nodes 2, 5, 8) - debugLog(` These nodes form the TOP side (${side}) of element ${elemIdx}`); + debugLog(` These nodes form the TOP side (${side}) of element ${elementIndex}`); } else if ( (node1Index === 6 && node2Index === 8) || (node1Index === 8 && node2Index === 6) || @@ -302,13 +315,13 @@ export class Mesh { (node1Index === 8 && node2Index === 7) ) { side = 3; // Right side (nodes 6, 7, 8) - debugLog(` These nodes form the RIGHT side (${side}) of element ${elemIdx}`); + debugLog(` These nodes form the RIGHT side (${side}) of element ${elementIndex}`); } // Add the element and side to the boundary elements array - this.parsedMesh.boundaryElements[prop.tag].push([elemIdx, side]); + this.parsedMesh.boundaryElements[prop.tag].push([elementIndex, side]); debugLog( - ` Added element-side pair [${elemIdx}, ${side}] to boundary tag ${prop.tag}` + ` Added element-side pair [${elementIndex}, ${side}] to boundary tag ${prop.tag}` ); foundElement = true; break; @@ -398,7 +411,7 @@ export class Mesh1D extends Mesh { } } // Generate nodal numbering (NOP) array - const nodalNumbering = this.generate1DNodalNumbering(this.numElementsX, totalNodesX, this.elementOrder); + const nodalNumbering = this.generateNodalNumbering1D(this.numElementsX, totalNodesX, this.elementOrder); // Find boundary elements const boundaryElements = this.findBoundaryElements(); @@ -421,7 +434,7 @@ export class Mesh1D extends Mesh { * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic' * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh */ - generate1DNodalNumbering(numElementsX, totalNodesX, elementOrder) { + generateNodalNumbering1D(numElementsX, totalNodesX, elementOrder) { // TODO: The totalNodesX is not used in the original function. Verify if // there is a multiple calculation on the totalNodes. @@ -462,18 +475,16 @@ export class Mesh1D extends Mesh { } /** - * Function to find the elements that belong to each boundary of a domain + * Function to find the elements that belong to each boundary of an 1D domain * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side * of the reference element is in contact with the physical boundary: - * - * For 1D domains (line segments): * 0 - Left node of reference element (maps to physical left endpoint) * 1 - Right node of reference element (maps to physical right endpoint) */ findBoundaryElements() { const boundaryElements = []; - const maxSides = 2; // For 1D, we only have two sides (left and right) + const maxSides = 2; // Two sides for 1D case (left and right) for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) { boundaryElements.push([]); } @@ -582,7 +593,7 @@ export class Mesh2D extends Mesh { } // Generate nodal numbering (NOP) array - const nodalNumbering = this.generate2DNodalNumbering( + const nodalNumbering = this.generateNodalNumbering2D( this.numElementsX, this.numElementsY, totalNodesY, @@ -616,7 +627,7 @@ export class Mesh2D extends Mesh { * @param {string} elementOrder - The order of elements, either 'linear' or 'quadratic' * @returns {array} NOP - A two-dimensional array which represents the element-to-node connectivity for the entire mesh */ - generate2DNodalNumbering(numElementsX, numElementsY, totalNodesY, elementOrder) { + generateNodalNumbering2D(numElementsX, numElementsY, totalNodesY, elementOrder) { let elementIndex = 0; let nop = []; @@ -673,20 +684,18 @@ export class Mesh2D extends Mesh { } /** - * Function to find the elements that belong to each boundary of a domain + * Function to find the elements that belong to each boundary of a 2D domain * @returns {array} An array containing arrays of elements and their adjacent boundary side for each boundary * Each element in the array is of the form [elementIndex, side], where 'side' indicates which side * of the reference element is in contact with the physical boundary: - * - * For 2D domains (rectangular): - * 0 - Bottom side of reference element (maps to physical bottom boundary) - * 1 - Left side of reference element (maps to physical left boundary) - * 2 - Top side of reference element (maps to physical top boundary) - * 3 - Right side of reference element (maps to physical right boundary) + * 0 - Bottom side of reference element (maps to physical bottom boundary in the case of a rectangular domain) + * 1 - Left side of reference element (maps to physical left boundary in the case of a rectangular domain) + * 2 - Top side of reference element (maps to physical top boundary in the case of a rectangular domain) + * 3 - Right side of reference element (maps to physical right boundary in the case of a rectangular domain) */ findBoundaryElements() { const boundaryElements = []; - const maxSides = 4; // For 2D, we have four sides (left, right, bottom, top) + const maxSides = 4; // Four sides for a rectangle 2D case (left, right, bottom, top) for (let sideIndex = 0; sideIndex < maxSides; sideIndex++) { boundaryElements.push([]); diff --git a/src/mesh/meshUtilsScript.js b/src/mesh/meshUtilsScript.js index 0167a55..7975fbe 100644 --- a/src/mesh/meshUtilsScript.js +++ b/src/mesh/meshUtilsScript.js @@ -1,11 +1,13 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ +// Internal imports import { BasisFunctions } from "./basisFunctionsScript.js"; import { Mesh1D, Mesh2D } from "./meshGenerationScript.js"; import { NumericalIntegration } from "../methods/numericalIntegrationScript.js"; @@ -29,7 +31,7 @@ export function prepareMesh(meshConfig) { errorLog("Mesh dimension must be either '1D' or '2D'."); } - // Use the parsed mesh in case it was already passed with Gmsh format + // Use the parsed mesh (e.g., from a Gmsh .msh import) if provided. Otherwise, generate a structured mesh const nodesCoordinatesAndNumbering = mesh.boundaryElementsProcessed ? mesh.parsedMesh : mesh.generateMesh(); // Extract nodes coordinates and nodal numbering (NOP) from the mesh data @@ -111,7 +113,7 @@ export function initializeFEA(meshData) { let gaussWeights = gaussPointsAndWeights.gaussWeights; // Determine the number of nodes in the reference element based on the first element in the nop array - const numNodes = nop[0].length; + const nodesPerElement = nop[0].length; return { residualVector, @@ -120,7 +122,7 @@ export function initializeFEA(meshData) { basisFunctions, gaussPoints, gaussWeights, - numNodes, + nodesPerElement, }; } @@ -130,13 +132,14 @@ export function initializeFEA(meshData) { * @returns {object} An object containing the mapped data */ export function performIsoparametricMapping1D(params) { - const { basisFunction, basisFunctionDerivKsi, nodesXCoordinates, localToGlobalMap, numNodes } = params; + const { basisFunction, basisFunctionDerivKsi, nodesXCoordinates, localToGlobalMap, nodesPerElement } = + params; let xCoordinates = 0; let ksiDerivX = 0; // Isoparametric mapping - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) { xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex]; ksiDerivX += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex]; } @@ -144,7 +147,7 @@ export function performIsoparametricMapping1D(params) { // Compute x-derivative of basis functions let basisFunctionDerivX = []; - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) { basisFunctionDerivX[localNodeIndex] = basisFunctionDerivKsi[localNodeIndex] / detJacobian; } @@ -168,7 +171,7 @@ export function performIsoparametricMapping2D(params) { nodesXCoordinates, nodesYCoordinates, localToGlobalMap, - numNodes, + nodesPerElement, } = params; let xCoordinates = 0; @@ -179,7 +182,7 @@ export function performIsoparametricMapping2D(params) { let etaDerivY = 0; // Isoparametric mapping - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) { xCoordinates += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex]; yCoordinates += nodesYCoordinates[localToGlobalMap[localNodeIndex]] * basisFunction[localNodeIndex]; ksiDerivX += nodesXCoordinates[localToGlobalMap[localNodeIndex]] * basisFunctionDerivKsi[localNodeIndex]; @@ -192,7 +195,7 @@ export function performIsoparametricMapping2D(params) { // Compute x-derivative and y-derivative of basis functions let basisFunctionDerivX = []; let basisFunctionDerivY = []; - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) { // The x-derivative of the n basis function basisFunctionDerivX[localNodeIndex] = (etaDerivY * basisFunctionDerivKsi[localNodeIndex] - @@ -213,3 +216,200 @@ export function performIsoparametricMapping2D(params) { basisFunctionDerivY, }; } + +/** + * Function to test if a point is inside a triangle using barycentric coordinates, + * also returning the natural coordinates (ksi, eta). + * @param {number} x - X-coordinate of the point + * @param {number} y - Y-coordinate of the point + * @param {array} vertices - Triangle vertices [[x0,y0],[x1,y1],[x2,y2]] + * @returns {object} Object containing inside boolean and natural coordinates {inside, ksi, eta} + */ +export function pointInsideTriangle(x, y, vertices) { + const tolerance = 1e-12; + const [v0, v1, v2] = vertices; + + const denom = (v1[1] - v2[1]) * (v0[0] - v2[0]) + (v2[0] - v1[0]) * (v0[1] - v2[1]); + + const ksi = ((v1[1] - v2[1]) * (x - v2[0]) + (v2[0] - v1[0]) * (y - v2[1])) / denom; + const eta = ((v2[1] - v0[1]) * (x - v2[0]) + (v0[0] - v2[0]) * (y - v2[1])) / denom; + const gamma = 1 - ksi - eta; + + const inside = ksi >= -tolerance && eta >= -tolerance && gamma >= -tolerance; + return { inside, ksi, eta }; +} + +/** + * Function to test if a point is inside a quadrilateral by spliting it into triangles and using barycentric coordinates + * @param {number} x - X-coordinate of the point + * @param {number} y - Y-coordinate of the point + * @param {array} vertices - Quadrilateral vertices [[x0,y0],[x1,y1],[x2,y2],[x3,y3]] + * @returns {object} Object containing inside boolean and natural coordinates {inside, ksi, eta} + */ +export function pointInsideQuadrilateral(x, y, vertices) { + const [firstTriangleVertices, secondTriangleVertices] = splitQuadrilateral(vertices); + const pointInsideFirstTriangle = pointInsideTriangle(x, y, firstTriangleVertices); + const pointInsideSecondTriangle = pointInsideTriangle(x, y, secondTriangleVertices); + + const inside = pointInsideFirstTriangle.inside || pointInsideSecondTriangle.inside; + let ksi = 0; + let eta = 0; + + if (inside) { + const [v0, v1, v2, v3] = vertices; + + // Function to calculate distance from point to line segment + const getDistanceFromLine = (p1, p2) => { + const num = Math.abs((p2[0] - p1[0]) * (p1[1] - y) - (p1[0] - x) * (p2[1] - p1[1])); + const den = Math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2); + return num / den; + }; + + // Calculate distances to edges based on vertex order: + // 1 (v1) --- 3 (v3) + // | | + // 0 (v0) --- 2 (v2) + + const distLeft = getDistanceFromLine(v0, v1); + const distRight = getDistanceFromLine(v2, v3); + const distBottom = getDistanceFromLine(v0, v2); + const distTop = getDistanceFromLine(v1, v3); + + ksi = distLeft / (distLeft + distRight); + eta = distBottom / (distBottom + distTop); + } + + return { inside, ksi, eta }; +} + +/** + * Function to split the quadrilateral elements into two triangles + * @param {array} vertices - Quadrilateral vertices [[x0,y0],[x1,y1],[x2,y2],[x3,y3]] + * @returns {array} Array of triangle vertices: [[v0,v1,v3], [v0,v2,v3]] + */ +export function splitQuadrilateral(vertices) { + const [v0, v1, v2, v3] = vertices; + // Vertices order: + // 1 --- 3 + // | | + // 0 --- 2 + return [ + [v0, v1, v3], + [v0, v2, v3], + ]; +} + +/** + * Function that finds the list of adjacent elements for each node in the mesh + * @param {object} meshData - Object containing nodal numbering (NOP) + * @returns {object} Object containing: + * - nodeNeighbors: Indices of neighboring elements per node + * - neighborCount: Total number of neighboring elements per node + */ +export function computeNodeNeighbors(meshData) { + const { nop, nodesXCoordinates } = meshData; + const totalNodes = nodesXCoordinates.length; + const nodesPerElement = nop[0].length; + + // Initialize arrays + const nodeNeighbors = Array.from({ length: totalNodes }, () => []); + const neighborCount = Array(totalNodes).fill(0); + + // Loop through all elements + for (let elemIndex = 0; elemIndex < nop.length; elemIndex++) { + for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) { + const nodeIndex = nop[elemIndex][localNodeIndex] - 1; + + // Increment the total number of neighboring elements for this node + neighborCount[nodeIndex] = neighborCount[nodeIndex] + 1; + + // Store the element index as a neighbor of this node + nodeNeighbors[nodeIndex].push(elemIndex); + } + } + + return { nodeNeighbors, neighborCount }; +} + +/** + * Function to extracts boundary line segments for ray casting + * @param {object} meshData - Object containing mesh data + * @returns {array} Array of segments + */ +export function getBoundarySegments(meshData) { + let boundaryLineElements = []; + let boundaryNodesSegments = []; + let boundaryGlobalElementIndex = 0; + let boundarySides; + const { nodesXCoordinates, nodesYCoordinates, nop, boundaryElements, meshDimension, elementOrder } = + meshData; + + if (meshDimension === "1D") { + if (elementOrder === "linear") { + boundarySides = { + 0: [0], // Node at the left side of the reference element + 1: [1], // Node at the right side of the reference element + }; + } else if (elementOrder === "quadratic") { + boundarySides = { + 0: [0], // Node at the left side of the reference element + 1: [1], // Node at the right side of the reference element + }; + } + } else if (meshDimension === "2D") { + if (elementOrder === "linear") { + boundarySides = { + 0: [0, 2], // Nodes at the bottom side of the reference element + 1: [0, 1], // Nodes at the left side of the reference element + 2: [1, 3], // Nodes at the top side of the reference element + 3: [2, 3], // Nodes at the right side of the reference element + }; + } else if (elementOrder === "quadratic") { + boundarySides = { + 0: [0, 3, 6], // Nodes at the bottom side of the reference element + 1: [0, 1, 2], // Nodes at the left side of the reference element + 2: [2, 5, 8], // Nodes at the top side of the reference element + 3: [6, 7, 8], // Nodes at the right side of the reference element + }; + } + } + + // Iterate over all boundaries + for (let boundaryIndex = 0; boundaryIndex < boundaryElements.length; boundaryIndex++) { + // Iterate over all elements in the current boundary + for ( + let boundaryLocalElementIndex = 0; + boundaryLocalElementIndex < boundaryElements[boundaryIndex].length; + boundaryLocalElementIndex++ + ) { + boundaryLineElements[boundaryGlobalElementIndex] = + boundaryElements[boundaryIndex][boundaryLocalElementIndex]; + boundaryGlobalElementIndex++; + // Retrieve the element index and the side + const [elementIndex, side] = boundaryElements[boundaryIndex][boundaryLocalElementIndex]; + let boundaryLocalNodeIndices = boundarySides[side]; + let currentElementNodesX = []; + let currentElementNodesY = []; + + for ( + let boundaryLocalNodeIndex = 0; + boundaryLocalNodeIndex < boundaryLocalNodeIndices.length; + boundaryLocalNodeIndex++ + ) { + const globalNodeIndex = nop[elementIndex][boundaryLocalNodeIndices[boundaryLocalNodeIndex]] - 1; + + currentElementNodesX.push(nodesXCoordinates[globalNodeIndex]); + currentElementNodesY.push(nodesYCoordinates[globalNodeIndex]); + } + + // Create segments for this element + for (let k = 0; k < currentElementNodesX.length - 1; k++) { + boundaryNodesSegments.push([ + [currentElementNodesX[k], currentElementNodesY[k]], + [currentElementNodesX[k + 1], currentElementNodesY[k + 1]], + ]); + } + } + } + return boundaryNodesSegments; +} diff --git a/src/methods/euclideanNormScript.js b/src/methods/euclideanNormScript.js index 1afd74d..62e232a 100644 --- a/src/methods/euclideanNormScript.js +++ b/src/methods/euclideanNormScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ /** diff --git a/src/methods/frontalSolverScript.js b/src/methods/frontalSolverScript.js index 8e32d26..8114e86 100644 --- a/src/methods/frontalSolverScript.js +++ b/src/methods/frontalSolverScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Internal imports @@ -35,10 +36,10 @@ export function runFrontalSolver(assembleFront, meshData, boundaryConditions, op const FEAData = initializeFEA(meshData); const totalNodes = meshData.nodesXCoordinates.length; const numElements = meshData.totalElements; - const numNodes = FEAData.numNodes; + const nodesPerElement = FEAData.nodesPerElement; // Calculate required array sizes - initializeFrontalArrays(numNodes, numElements); + initializeFrontalArrays(nodesPerElement, numElements); // Start timing for system solving (frontal algorithm) basicLog("Solving system using frontal..."); @@ -52,7 +53,7 @@ export function runFrontalSolver(assembleFront, meshData, boundaryConditions, op // Copy node connectivity array into frontalData storage for (let elementIndex = 0; elementIndex < meshData.totalElements; elementIndex++) { - for (let nodeIndex = 0; nodeIndex < FEAData.numNodes; nodeIndex++) { + for (let nodeIndex = 0; nodeIndex < FEAData.nodesPerElement; nodeIndex++) { frontalData.nodalNumbering[elementIndex][nodeIndex] = meshData.nop[elementIndex][nodeIndex]; } } @@ -106,7 +107,7 @@ export function runFrontalSolver(assembleFront, meshData, boundaryConditions, op frontalState.determinant = 1; for (let elementIndex = 0; elementIndex < meshData.totalElements; elementIndex++) { - frontalState.nodesPerElement[elementIndex] = FEAData.numNodes; + frontalState.nodesPerElement[elementIndex] = FEAData.nodesPerElement; } // Parameters for non-linear assemblers @@ -156,41 +157,41 @@ export function runFrontalSolver(assembleFront, meshData, boundaryConditions, op /** * Function to initialize arrays dynamically based on problem size - * @param {number} numNodes - Number of nodes per element + * @param {number} nodesPerElement - Number of nodes per element * @param {number} numElements - Number of elements in the mesh */ -function initializeFrontalArrays(numNodes, numElements) { +function initializeFrontalArrays(nodesPerElement, numElements) { // Use the actual number of elements from the mesh frontalData.nodalNumbering = Array(numElements) .fill() - .map(() => Array(numNodes).fill(0)); - frontalData.nodeConstraintCode = Array(numNodes).fill(0); - frontalData.boundaryValues = Array(numNodes).fill(0); - frontalData.globalResidualVector = Array(numNodes).fill(0); - frontalData.solutionVector = Array(numNodes).fill(0); + .map(() => Array(nodesPerElement).fill(0)); + frontalData.nodeConstraintCode = Array(nodesPerElement).fill(0); + frontalData.boundaryValues = Array(nodesPerElement).fill(0); + frontalData.globalResidualVector = Array(nodesPerElement).fill(0); + frontalData.solutionVector = Array(nodesPerElement).fill(0); frontalData.topologyData = Array(numElements).fill(0); frontalData.lateralData = Array(numElements).fill(0); // Initialize frontalState arrays frontalState.writeFlag = 0; - frontalState.totalNodes = numNodes; + frontalState.totalNodes = nodesPerElement; frontalState.transformationFlag = 0; frontalState.nodesPerElement = Array(numElements).fill(0); frontalState.determinant = 1; // For matrix operations, estimate required size based on problem complexity - const systemSize = Math.max(numNodes, 2000); + const systemSize = Math.max(nodesPerElement, 2000); frontalState.globalSolutionVector = Array(systemSize).fill(0); frontalState.frontDataIndex = 0; // Initialize elementData arrays - elementData.localJacobianMatrix = Array(numNodes) + elementData.localJacobianMatrix = Array(nodesPerElement) .fill() - .map(() => Array(numNodes).fill(0)); + .map(() => Array(nodesPerElement).fill(0)); elementData.currentElementIndex = 0; // Initialize frontStorage arrays - const frontSize = estimateFrontSize(numNodes, numElements); + const frontSize = estimateFrontSize(nodesPerElement, numElements); frontStorage.frontValues = Array(frontSize).fill(0); frontStorage.columnHeaders = Array(systemSize).fill(0); frontStorage.pivotRow = Array(systemSize).fill(0); @@ -199,18 +200,18 @@ function initializeFrontalArrays(numNodes, numElements) { /** * Function to estimate the required front size - * @param {number} numNodes - Number of of nodes per element + * @param {number} nodesPerElement - Number of of nodes per element * @param {number} numElements - Number of elements in the mesh * @returns {number} Estimated front size */ -function estimateFrontSize(numNodes, numElements) { - const frontWidthEstimate = Math.max(Math.ceil(Math.sqrt(numElements)) * numNodes, numNodes * 2); +function estimateFrontSize(nodesPerElement, numElements) { + const frontWidthEstimate = Math.max(Math.ceil(Math.sqrt(numElements)) * nodesPerElement, nodesPerElement * 2); return frontWidthEstimate * numElements; } // Old function to estimate the required front size -// function estimateFrontSize(numNodes, numElements, numNodes) { -// const frontWidthEstimate = Math.ceil(Math.sqrt(numElements) * numNodes * 2); -// const frontSize = frontWidthEstimate * numNodes * 4; +// function estimateFrontSize(nodesPerElement, numElements, nodesPerElement) { +// const frontWidthEstimate = Math.ceil(Math.sqrt(numElements) * nodesPerElement * 2); +// const frontSize = frontWidthEstimate * nodesPerElement * 4; // return Math.max(frontSize, 10000); // } @@ -243,10 +244,10 @@ function assembleElementContribution(meshData, FEAData, thermalBoundaryCondition }); // Handle Robin-type boundary conditions differently based on which solver is being used - let boundaryLocalJacobianMatrix = Array(FEAData.numNodes) + let boundaryLocalJacobianMatrix = Array(FEAData.nodesPerElement) .fill() - .map(() => Array(FEAData.numNodes).fill(0)); - let boundaryResidualVector = Array(FEAData.numNodes).fill(0); + .map(() => Array(FEAData.nodesPerElement).fill(0)); + let boundaryResidualVector = Array(FEAData.nodesPerElement).fill(0); // heatConductionScript solver if (assembleFront === assembleHeatConductionFront) { @@ -255,7 +256,7 @@ function assembleElementContribution(meshData, FEAData, thermalBoundaryCondition for (const boundaryKey in meshData.boundaryElements) { if ( thermalBoundaryConditions.boundaryConditions[boundaryKey]?.[0] === "convection" && - meshData.boundaryElements[boundaryKey].some(([elemIdx, _]) => elemIdx === elementIndex) + meshData.boundaryElements[boundaryKey].some(([boundaryElementIndex, _]) => boundaryElementIndex === elementIndex) ) { isOnRobinTypeBoundary = true; break; @@ -281,15 +282,15 @@ function assembleElementContribution(meshData, FEAData, thermalBoundaryCondition } // Combine domain and boundary contributions - for (let localNodeI = 0; localNodeI < FEAData.numNodes; localNodeI++) { - for (let localNodeJ = 0; localNodeJ < FEAData.numNodes; localNodeJ++) { + for (let localNodeI = 0; localNodeI < FEAData.nodesPerElement; localNodeI++) { + for (let localNodeJ = 0; localNodeJ < FEAData.nodesPerElement; localNodeJ++) { elementData.localJacobianMatrix[localNodeI][localNodeJ] = localJacobianMatrix[localNodeI][localNodeJ] + boundaryLocalJacobianMatrix[localNodeI][localNodeJ]; } } // Assemble local element residual - for (let localNodeIndex = 0; localNodeIndex < FEAData.numNodes; localNodeIndex++) { + for (let localNodeIndex = 0; localNodeIndex < FEAData.nodesPerElement; localNodeIndex++) { const globalNodeIndex = ngl[localNodeIndex] - 1; frontalData.globalResidualVector[globalNodeIndex] += localResidualVector[localNodeIndex] + boundaryResidualVector[localNodeIndex]; @@ -308,10 +309,10 @@ function assembleElementContribution(meshData, FEAData, thermalBoundaryCondition function runFrontalAlgorithm(meshData, FEAData, thermalBoundaryConditions, assembleFront) { // Allocate local arrays dynamically const totalElements = meshData.totalElements; - const numNodes = meshData.nodesXCoordinates.length; - const systemSize = Math.max(numNodes, frontalState.globalSolutionVector.length); - let localDestination = Array(FEAData.numNodes).fill(0); - let rowDestination = Array(FEAData.numNodes).fill(0); + const nodesPerElement = meshData.nodesXCoordinates.length; + const systemSize = Math.max(nodesPerElement, frontalState.globalSolutionVector.length); + let localDestination = Array(FEAData.nodesPerElement).fill(0); + let rowDestination = Array(FEAData.nodesPerElement).fill(0); let rowHeaders = Array(systemSize).fill(0); let pivotRowIndices = Array(systemSize).fill(0); let pivotColumnIndices = Array(systemSize).fill(0); @@ -320,9 +321,9 @@ function runFrontalAlgorithm(meshData, FEAData, thermalBoundaryConditions, assem let frontMatrix = Array(systemSize) .fill() .map(() => Array(systemSize).fill(0)); - let rowSwapCount = Array(numNodes).fill(0); - let columnSwapCount = Array(numNodes).fill(0); - let lastAppearanceCheck = Array(numNodes).fill(0); + let rowSwapCount = Array(nodesPerElement).fill(0); + let columnSwapCount = Array(nodesPerElement).fill(0); + let lastAppearanceCheck = Array(nodesPerElement).fill(0); let pivotColumnGlobalIndex; // Pivot column global index let frontDataCounter = 1; diff --git a/src/methods/jacobiSolverScript.js b/src/methods/jacobiSolverScript.js index a820614..f497235 100644 --- a/src/methods/jacobiSolverScript.js +++ b/src/methods/jacobiSolverScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ /** diff --git a/src/methods/linearSystemSolverScript.js b/src/methods/linearSystemSolverScript.js index 6bf3ee9..5d42efd 100644 --- a/src/methods/linearSystemSolverScript.js +++ b/src/methods/linearSystemSolverScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Internal imports diff --git a/src/methods/newtonRaphsonScript.js b/src/methods/newtonRaphsonScript.js index 8eac9d3..636cb8f 100644 --- a/src/methods/newtonRaphsonScript.js +++ b/src/methods/newtonRaphsonScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Internal imports diff --git a/src/methods/numericalIntegrationScript.js b/src/methods/numericalIntegrationScript.js index ec5ee57..9085918 100644 --- a/src/methods/numericalIntegrationScript.js +++ b/src/methods/numericalIntegrationScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ /** diff --git a/src/methods/webgpuJacobiSolverScript.js b/src/methods/webgpuJacobiSolverScript.js index 7724438..084fbe0 100644 --- a/src/methods/webgpuJacobiSolverScript.js +++ b/src/methods/webgpuJacobiSolverScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // External imports diff --git a/src/models/frontPropagationScript.js b/src/models/frontPropagationScript.js index 4c7d4d3..66843fd 100644 --- a/src/models/frontPropagationScript.js +++ b/src/models/frontPropagationScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Internal imports @@ -61,13 +62,13 @@ export function assembleFrontPropagationMat( basisFunctions, gaussPoints, gaussWeights, - numNodes, + nodesPerElement, } = FEAData; // Matrix assembly for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) { // Map local element nodes to global mesh nodes - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) { // Subtract 1 from nop in order to start numbering from 0 localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1; } @@ -88,7 +89,7 @@ export function assembleFrontPropagationMat( basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi, nodesXCoordinates, localToGlobalMap, - numNodes, + nodesPerElement, }); // Extract mapping results @@ -97,18 +98,18 @@ export function assembleFrontPropagationMat( // Calculate solution derivative let solutionDerivX = 0; - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) { solutionDerivX += solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex]; } // Computation of Galerkin's residuals and Jacobian matrix - for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) { + for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) { let localToGlobalMap1 = localToGlobalMap[localNodeIndex1]; // residualVector // TODO residualVector calculation here - for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) { + for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; localNodeIndex2++) { let localToGlobalMap2 = localToGlobalMap[localNodeIndex2]; // jacobianMatrix // TODO jacobianMatrix calculation here @@ -132,7 +133,7 @@ export function assembleFrontPropagationMat( nodesXCoordinates, nodesYCoordinates, localToGlobalMap, - numNodes, + nodesPerElement, }); // Extract mapping results @@ -142,7 +143,7 @@ export function assembleFrontPropagationMat( // Calculate solution derivatives let solutionDerivX = 0; let solutionDerivY = 0; - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) { solutionDerivX += solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex]; solutionDerivY += @@ -150,7 +151,7 @@ export function assembleFrontPropagationMat( } // Computation of Galerkin's residuals and Jacobian matrix - for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) { + for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) { let localToGlobalMap1 = localToGlobalMap[localNodeIndex1]; // residualVector: Viscous term contribution (to stabilize the solution) @@ -183,7 +184,7 @@ export function assembleFrontPropagationMat( basisFunction[localNodeIndex1]); } - for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) { + for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; localNodeIndex2++) { let localToGlobalMap2 = localToGlobalMap[localNodeIndex2]; // jacobianMatrix: Viscous term contribution @@ -267,22 +268,22 @@ export function assembleFrontPropagationFront({ eikonalActivationFlag, }) { // Extract numerical integration parameters and mesh coordinates - const { gaussPoints, gaussWeights, numNodes } = FEAData; + const { gaussPoints, gaussWeights, nodesPerElement } = FEAData; const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData; // Calculate eikonal viscous term let eikonalViscousTerm = 1 - eikonalActivationFlag + baseEikonalViscousTerm; // Viscous term for the front propagation (eikonal) equation // Initialize local Jacobian matrix and local residual vector - const localJacobianMatrix = Array(numNodes) + const localJacobianMatrix = Array(nodesPerElement) .fill() - .map(() => Array(numNodes).fill(0)); - const localResidualVector = Array(numNodes).fill(0); + .map(() => Array(nodesPerElement).fill(0)); + const localResidualVector = Array(nodesPerElement).fill(0); // Build the mapping from local node indices to global node indices - const ngl = Array(numNodes); - const localToGlobalMap = Array(numNodes); - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + const ngl = Array(nodesPerElement); + const localToGlobalMap = Array(nodesPerElement); + for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) { ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]); localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1; } @@ -303,7 +304,7 @@ export function assembleFrontPropagationFront({ basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi, nodesXCoordinates, localToGlobalMap, - numNodes, + nodesPerElement, }); // Extract mapping results @@ -312,18 +313,18 @@ export function assembleFrontPropagationFront({ // Calculate solution derivative let solutionDerivX = 0; - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) { solutionDerivX += solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex]; } // Computation of Galerkin's residuals and Jacobian matrix - for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) { + for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) { let localToGlobalMap1 = localToGlobalMap[localNodeIndex1]; // residualVector // TODO residualVector calculation here - for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) { + for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; localNodeIndex2++) { let localToGlobalMap2 = localToGlobalMap[localNodeIndex2]; // localJacobianMatrix // TODO localJacobianMatrix calculation here @@ -344,13 +345,13 @@ export function assembleFrontPropagationFront({ nodesXCoordinates, nodesYCoordinates, localToGlobalMap, - numNodes, + nodesPerElement, }); // Calculate solution derivatives let solutionDerivX = 0; let solutionDerivY = 0; - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) { solutionDerivX += solutionVector[localToGlobalMap[localNodeIndex]] * basisFunctionDerivX[localNodeIndex]; solutionDerivY += @@ -358,7 +359,7 @@ export function assembleFrontPropagationFront({ } // Computation of Galerkin's residuals and Jacobian matrix - for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) { + for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) { let localToGlobalMap1 = localToGlobalMap[localNodeIndex1]; // Viscous term contribution localResidualVector[localNodeIndex1] += @@ -390,7 +391,7 @@ export function assembleFrontPropagationFront({ basisFunction[localNodeIndex1]); } - for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) { + for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; localNodeIndex2++) { // Viscous term contribution localJacobianMatrix[localNodeIndex1][localNodeIndex2] -= eikonalViscousTerm * diff --git a/src/models/generalFormPDEScript.js b/src/models/generalFormPDEScript.js index 2634654..2b5939f 100644 --- a/src/models/generalFormPDEScript.js +++ b/src/models/generalFormPDEScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Internal imports @@ -46,7 +47,7 @@ export function assembleGeneralFormPDEMat(meshData, boundaryConditions, coeffici basisFunctions, gaussPoints, gaussWeights, - numNodes, + nodesPerElement, } = FEAData; if (meshDimension === "1D") { @@ -55,7 +56,7 @@ export function assembleGeneralFormPDEMat(meshData, boundaryConditions, coeffici // Matrix assembly for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) { // Map local element nodes to global mesh nodes - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) { // Convert to 0-based indexing localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1; } @@ -73,12 +74,12 @@ export function assembleGeneralFormPDEMat(meshData, boundaryConditions, coeffici basisFunctionDerivKsi, nodesXCoordinates, localToGlobalMap, - numNodes, + nodesPerElement, }); // Calculate the physical coordinate for this Gauss point let xCoord = 0; - for (let i = 0; i < numNodes; i++) { + for (let i = 0; i < nodesPerElement; i++) { xCoord += nodesXCoordinates[localToGlobalMap[i]] * basisFunction[i]; } @@ -89,14 +90,14 @@ export function assembleGeneralFormPDEMat(meshData, boundaryConditions, coeffici const d = D(xCoord); // Computation of Galerkin's residuals and local Jacobian matrix - for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) { + for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) { const globalNodeIndex1 = localToGlobalMap[localNodeIndex1]; // Source term contribution to residual vector residualVector[globalNodeIndex1] -= gaussWeights[gaussPointIndex] * detJacobian * d * basisFunction[localNodeIndex1]; - for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) { + for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; localNodeIndex2++) { const globalNodeIndex2 = localToGlobalMap[localNodeIndex2]; // Diffusion term @@ -165,20 +166,20 @@ export function assembleGeneralFormPDEFront({ coefficientFunctions, }) { // Extract numerical integration parameters and mesh coordinates - const { gaussPoints, gaussWeights, numNodes } = FEAData; + const { gaussPoints, gaussWeights, nodesPerElement } = FEAData; const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData; const { A, B, C, D } = coefficientFunctions; // Initialize local Jacobian matrix and local residual vector - const localJacobianMatrix = Array(numNodes) + const localJacobianMatrix = Array(nodesPerElement) .fill() - .map(() => Array(numNodes).fill(0)); - const localResidualVector = Array(numNodes).fill(0); + .map(() => Array(nodesPerElement).fill(0)); + const localResidualVector = Array(nodesPerElement).fill(0); // Build the mapping from local node indices to global node indices - const ngl = Array(numNodes); - const localToGlobalMap = Array(numNodes); - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + const ngl = Array(nodesPerElement); + const localToGlobalMap = Array(nodesPerElement); + for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) { ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]); localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1; } @@ -199,12 +200,12 @@ export function assembleGeneralFormPDEFront({ basisFunctionDerivKsi, nodesXCoordinates, localToGlobalMap, - numNodes, + nodesPerElement, }); // Calculate the physical coordinate for this Gauss point let xCoord = 0; - for (let i = 0; i < numNodes; i++) { + for (let i = 0; i < nodesPerElement; i++) { xCoord += nodesXCoordinates[localToGlobalMap[i]] * basisFunction[i]; } @@ -215,12 +216,12 @@ export function assembleGeneralFormPDEFront({ const d = D(xCoord); // Computation of local Jacobian matrix and residual vector - for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) { + for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) { // Source term contribution to local residual vector localResidualVector[localNodeIndex1] -= gaussWeights[gaussPointIndex] * detJacobian * d * basisFunction[localNodeIndex1]; - for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) { + for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; localNodeIndex2++) { // Diffusion term localJacobianMatrix[localNodeIndex1][localNodeIndex2] += gaussWeights[gaussPointIndex] * diff --git a/src/models/genericBoundaryConditionsScript.js b/src/models/genericBoundaryConditionsScript.js index 5e471f4..66b36d0 100644 --- a/src/models/genericBoundaryConditionsScript.js +++ b/src/models/genericBoundaryConditionsScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Internal imports @@ -73,7 +74,7 @@ export class GenericBoundaryConditions { } else if (this.elementOrder === "quadratic") { const boundarySides = { 0: [0], // Node at the left side of the reference element - 2: [2], // Node at the right side of the reference element + 1: [2], // Node at the right side of the reference element }; boundarySides[side].forEach((nodeIndex) => { const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1; diff --git a/src/models/heatConductionScript.js b/src/models/heatConductionScript.js index 6273071..842c632 100644 --- a/src/models/heatConductionScript.js +++ b/src/models/heatConductionScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Internal imports @@ -54,13 +55,13 @@ export function assembleHeatConductionMat(meshData, boundaryConditions) { basisFunctions, gaussPoints, gaussWeights, - numNodes, + nodesPerElement, } = FEAData; // Matrix assembly for (let elementIndex = 0; elementIndex < totalElements; elementIndex++) { // Map local element nodes to global mesh nodes - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) { // Subtract 1 from nop in order to start numbering from 0 localToGlobalMap[localNodeIndex] = nop[elementIndex][localNodeIndex] - 1; } @@ -78,18 +79,18 @@ export function assembleHeatConductionMat(meshData, boundaryConditions) { basisFunctionDerivKsi: basisFunctionsAndDerivatives.basisFunctionDerivKsi, nodesXCoordinates, localToGlobalMap, - numNodes, + nodesPerElement, }); // Extract mapping results const { detJacobian, basisFunctionDerivX } = mappingResult; // Computation of Galerkin's residuals and Jacobian matrix - for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) { + for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) { let localToGlobalMap1 = localToGlobalMap[localNodeIndex1]; // residualVector is zero for this case - for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) { + for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; localNodeIndex2++) { let localToGlobalMap2 = localToGlobalMap[localNodeIndex2]; jacobianMatrix[localToGlobalMap1][localToGlobalMap2] += -gaussWeights[gaussPointIndex1] * @@ -115,18 +116,18 @@ export function assembleHeatConductionMat(meshData, boundaryConditions) { nodesXCoordinates, nodesYCoordinates, localToGlobalMap, - numNodes, + nodesPerElement, }); // Extract mapping results const { detJacobian, basisFunctionDerivX, basisFunctionDerivY } = mappingResult; // Computation of Galerkin's residuals and Jacobian matrix - for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) { + for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) { let localToGlobalMap1 = localToGlobalMap[localNodeIndex1]; // residualVector is zero for this case - for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) { + for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; localNodeIndex2++) { let localToGlobalMap2 = localToGlobalMap[localNodeIndex2]; jacobianMatrix[localToGlobalMap1][localToGlobalMap2] += -gaussWeights[gaussPointIndex1] * @@ -185,19 +186,19 @@ export function assembleHeatConductionMat(meshData, boundaryConditions) { */ export function assembleHeatConductionFront({ elementIndex, nop, meshData, basisFunctions, FEAData }) { // Extract numerical integration parameters and mesh coordinates - const { gaussPoints, gaussWeights, numNodes } = FEAData; + const { gaussPoints, gaussWeights, nodesPerElement } = FEAData; const { nodesXCoordinates, nodesYCoordinates, meshDimension } = meshData; // Initialize local Jacobian matrix and local residual vector - const localJacobianMatrix = Array(numNodes) + const localJacobianMatrix = Array(nodesPerElement) .fill() - .map(() => Array(numNodes).fill(0)); - const localResidualVector = Array(numNodes).fill(0); + .map(() => Array(nodesPerElement).fill(0)); + const localResidualVector = Array(nodesPerElement).fill(0); // Build the mapping from local node indices to global node indices - const ngl = Array(numNodes); - const localToGlobalMap = Array(numNodes); - for (let localNodeIndex = 0; localNodeIndex < numNodes; localNodeIndex++) { + const ngl = Array(nodesPerElement); + const localToGlobalMap = Array(nodesPerElement); + for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) { ngl[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]); localToGlobalMap[localNodeIndex] = Math.abs(nop[elementIndex][localNodeIndex]) - 1; } @@ -217,12 +218,12 @@ export function assembleHeatConductionFront({ elementIndex, nop, meshData, basis basisFunctionDerivKsi, nodesXCoordinates, localToGlobalMap, - numNodes, + nodesPerElement, }); // Computation of Galerkin's residuals and local Jacobian matrix - for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) { - for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) { + for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) { + for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; localNodeIndex2++) { localJacobianMatrix[localNodeIndex1][localNodeIndex2] -= gaussWeights[gaussPointIndex1] * detJacobian * @@ -249,12 +250,12 @@ export function assembleHeatConductionFront({ elementIndex, nop, meshData, basis nodesXCoordinates, nodesYCoordinates, localToGlobalMap, - numNodes, + nodesPerElement, }); // Computation of Galerkin's residuals and local Jacobian matrix - for (let localNodeIndex1 = 0; localNodeIndex1 < numNodes; localNodeIndex1++) { - for (let localNodeIndex2 = 0; localNodeIndex2 < numNodes; localNodeIndex2++) { + for (let localNodeIndex1 = 0; localNodeIndex1 < nodesPerElement; localNodeIndex1++) { + for (let localNodeIndex2 = 0; localNodeIndex2 < nodesPerElement; localNodeIndex2++) { localJacobianMatrix[localNodeIndex1][localNodeIndex2] -= gaussWeights[gaussPointIndex1] * gaussWeights[gaussPointIndex2] * diff --git a/src/models/thermalBoundaryConditionsScript.js b/src/models/thermalBoundaryConditionsScript.js index 624405d..6172e49 100644 --- a/src/models/thermalBoundaryConditionsScript.js +++ b/src/models/thermalBoundaryConditionsScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Internal imports @@ -75,7 +76,7 @@ export class ThermalBoundaryConditions { } else if (this.elementOrder === "quadratic") { const boundarySides = { 0: [0], // Node at the left side of the reference element - 2: [2], // Node at the right side of the reference element + 1: [2], // Node at the right side of the reference element }; boundarySides[side].forEach((nodeIndex) => { const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1; @@ -388,8 +389,8 @@ export class ThermalBoundaryConditions { let ksiDerivY = 0; let etaDerivX = 0; let etaDerivY = 0; - const numNodes = this.nop[elementIndex].length; - for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) { + const nodesPerElement = this.nop[elementIndex].length; + for (let nodeIndex = 0; nodeIndex < nodesPerElement; nodeIndex++) { const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1; // For boundaries along Ksi (horizontal), use Ksi derivatives @@ -487,8 +488,8 @@ export class ThermalBoundaryConditions { let ksiDerivY = 0; let etaDerivX = 0; let etaDerivY = 0; - const numNodes = this.nop[elementIndex].length; - for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) { + const nodesPerElement = this.nop[elementIndex].length; + for (let nodeIndex = 0; nodeIndex < nodesPerElement; nodeIndex++) { const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1; // For boundaries along Ksi (horizontal), use Ksi derivatives @@ -585,11 +586,11 @@ export class ThermalBoundaryConditions { }); // Initialize local Jacobian matrix and local residual vector - const numNodes = this.nop[elementIndex].length; - const localJacobianMatrix = Array(numNodes) + const nodesPerElement = this.nop[elementIndex].length; + const localJacobianMatrix = Array(nodesPerElement) .fill() - .map(() => Array(numNodes).fill(0)); - const localResidualVector = Array(numNodes).fill(0); + .map(() => Array(nodesPerElement).fill(0)); + const localResidualVector = Array(nodesPerElement).fill(0); // Check if this element is on a convection boundary for (const boundaryKey in this.boundaryElements) { @@ -602,7 +603,7 @@ export class ThermalBoundaryConditions { // Find if this element is on this boundary and which side const boundaryElement = this.boundaryElements[boundaryKey].find( - ([elemIdx, _]) => elemIdx === elementIndex + ([boundaryElementIndex, _]) => boundaryElementIndex === elementIndex ); if (boundaryElement) { @@ -671,7 +672,7 @@ export class ThermalBoundaryConditions { ksiDerivY = 0, etaDerivX = 0, etaDerivY = 0; - for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) { + for (let nodeIndex = 0; nodeIndex < nodesPerElement; nodeIndex++) { const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1; if (side === 0 || side === 2) { @@ -760,8 +761,8 @@ export class ThermalBoundaryConditions { let ksiDerivY = 0; let etaDerivX = 0; let etaDerivY = 0; - const numNodes = this.nop[elementIndex].length; - for (let nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) { + const nodesPerElement = this.nop[elementIndex].length; + for (let nodeIndex = 0; nodeIndex < nodesPerElement; nodeIndex++) { const globalNodeIndex = this.nop[elementIndex][nodeIndex] - 1; // For boundaries along Ksi (horizontal), use Ksi derivatives diff --git a/src/readers/gmshReaderScript.js b/src/readers/gmshReaderScript.js index 130e4da..46e4fc7 100644 --- a/src/readers/gmshReaderScript.js +++ b/src/readers/gmshReaderScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Internal imports diff --git a/src/utilities/loggingScript.js b/src/utilities/loggingScript.js index c453028..c16907f 100644 --- a/src/utilities/loggingScript.js +++ b/src/utilities/loggingScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // Global logging level diff --git a/src/visualization/plotSolutionScript.js b/src/visualization/plotSolutionScript.js index c31b8c1..744e2e7 100644 --- a/src/visualization/plotSolutionScript.js +++ b/src/visualization/plotSolutionScript.js @@ -1,29 +1,37 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ +// Internal imports +import { + prepareMesh, + pointInsideTriangle, + pointInsideQuadrilateral, + computeNodeNeighbors, + getBoundarySegments, +} from "../mesh/meshUtilsScript.js"; +import { BasisFunctions } from "../mesh/basisFunctionsScript.js"; +import { initializeFEA } from "../mesh/meshUtilsScript.js"; +import { basicLog, debugLog, errorLog } from "../utilities/loggingScript.js"; + /** * Function to create plots of the solution vector - * @param {*} solutionVector - The computed solution vector - * @param {*} nodesCoordinates - Object containing x and y coordinates for the nodes - * @param {string} solverConfig - Parameter specifying the type of solver - * @param {string} meshDimension - The dimension of the solution + * @param {object} result - Object containing solution vector and mesh information + * @param {object} model - Object containing model properties * @param {string} plotType - The type of plot * @param {string} plotDivId - The id of the div where the plot will be rendered */ -export function plotSolution( - solutionVector, - nodesCoordinates, - solverConfig, - meshDimension, - plotType, - plotDivId -) { - const { nodesXCoordinates, nodesYCoordinates } = nodesCoordinates; +export function plotSolution(model, result, plotType, plotDivId) { + const { nodesXCoordinates, nodesYCoordinates } = result.nodesCoordinates; + const solutionVector = result.solutionVector; + const solverConfig = model.solverConfig; + const meshDimension = model.meshConfig.meshDimension; + const meshData = prepareMesh(model.meshConfig); // Retrieve mesh connectivity details (used in splitQuadrilateral) if (meshDimension === "1D" && plotType === "line") { // Check if solutionVector is a nested array @@ -46,7 +54,7 @@ export function plotSolution( let maxWindowWidth = Math.min(window.innerWidth, 700); let plotWidth = Math.min(maxWindowWidth, 600); - let plotHeight = 350; + let plotHeight = 300; let layout = { title: `line plot - ${solverConfig}`, @@ -67,7 +75,7 @@ export function plotSolution( zData = solutionVector; } - // Sizing parameters + // Plot sizing parameters let maxWindowWidth = Math.min(window.innerWidth, 700); let maxX = Math.max(...nodesXCoordinates); let maxY = Math.max(...nodesYCoordinates); @@ -109,3 +117,302 @@ export function plotSolution( Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true }); } } + +/** + * Function to generate a dense visualization grid and interpolate the FEM solution on it + * @param {object} result - Object containing solution vector and mesh information + * @param {object} model - Object containing model properties + * @param {string} plotType - The type of plot + * @param {string} plotDivId - The id of the div where the plot will be rendered + */ +export function plotInterpolatedSolution(model, result, plotType, plotDivId) { + const { nodesXCoordinates, nodesYCoordinates } = result.nodesCoordinates; // TODO: Check if we should place it inside the 2D block + const meshDimension = model.meshConfig.meshDimension; + const meshData = prepareMesh(model.meshConfig); // Retrieve mesh connectivity details + + // Initialize BasisFunctions once here to avoid creating it inside the loop + const basisFunctions = new BasisFunctions({ + meshDimension: model.meshConfig.meshDimension, + elementOrder: model.meshConfig.elementOrder, + }); + + if (meshDimension === "1D" && plotType === "line") { + // 1D plot region + } else if (meshDimension === "2D" && plotType === "contour") { + const visNodeXCoordinates = []; + const visNodeYCoordinates = []; + let visSolution = []; + const visNodesX = 1e2; // Number of nodes along the x-axis of the visualization grid + const visNodesY = 1e2; // Number of nodes along the y-axis of the visualization grid + + // const { nodesXCoordinates, nodesYCoordinates } = result.nodesCoordinates; + const deltavisX = (Math.max(...nodesXCoordinates) - Math.min(...nodesXCoordinates)) / (visNodesX - 1); + const deltavisY = (Math.max(...nodesYCoordinates) - Math.min(...nodesYCoordinates)) / (visNodesY - 1); + + visNodeXCoordinates[0] = Math.min(...nodesXCoordinates); + visNodeYCoordinates[0] = Math.min(...nodesYCoordinates); + + for (let visNodeIndexY = 1; visNodeIndexY < visNodesY; visNodeIndexY++) { + visNodeXCoordinates[visNodeIndexY] = visNodeXCoordinates[0]; + visNodeYCoordinates[visNodeIndexY] = visNodeYCoordinates[0] + visNodeIndexY * deltavisY; + } + + for (let visNodeIndexX = 1; visNodeIndexX < visNodesX; visNodeIndexX++) { + const nnode = visNodeIndexX * visNodesY; + visNodeXCoordinates[nnode] = visNodeXCoordinates[0] + visNodeIndexX * deltavisX; + visNodeYCoordinates[nnode] = visNodeYCoordinates[0]; + + for (let visNodeIndexY = 1; visNodeIndexY < visNodesY; visNodeIndexY++) { + visNodeXCoordinates[nnode + visNodeIndexY] = visNodeXCoordinates[nnode]; + visNodeYCoordinates[nnode + visNodeIndexY] = visNodeYCoordinates[nnode] + visNodeIndexY * deltavisY; + } + } + + const visNodeCoordinates = { visNodeXCoordinates, visNodeYCoordinates }; + + // Initialize visSolution with null for all visualization nodes + visSolution = new Array(visNodesX * visNodesY).fill(null); + + // Get boundary segments for ray casting + const boundarySegments = getBoundarySegments(meshData); + + // Perform adjacency-based search to find which element contains a given point (quick search) + const { nodeNeighbors, neighborCount } = computeNodeNeighbors(meshData); + let lastParentElement = 0; + for (let visNodeIndex = 0; visNodeIndex < visNodesX * visNodesY; visNodeIndex++) { + // Ray casting check + if ( + !pointInsidePolygon( + visNodeXCoordinates[visNodeIndex], + visNodeYCoordinates[visNodeIndex], + boundarySegments + ) + ) { + continue; + } + let found = false; + for ( + let localNodeIndex = 0; + localNodeIndex < meshData.nop[lastParentElement].length; + localNodeIndex++ + ) { + let globalNodeIndex = meshData.nop[lastParentElement][localNodeIndex] - 1; + for ( + let neighborElementsIndex = 0; + neighborElementsIndex < neighborCount[globalNodeIndex]; + neighborElementsIndex++ + ) { + let currentElement = nodeNeighbors[globalNodeIndex][neighborElementsIndex]; + const searchResult = pointSearch( + model, + meshData, + result, + currentElement, + visNodeXCoordinates[visNodeIndex], + visNodeYCoordinates[visNodeIndex], + basisFunctions + ); + + if (searchResult.inside) { + lastParentElement = currentElement; + visSolution[visNodeIndex] = searchResult.value; + found = true; + break; + } + } + if (found) break; + } + + // Scan all elements to find which element contains a given point (slow search) + if (!found) { + for (let currentElement = 0; currentElement < meshData.nop.length; currentElement++) { + const searchResult = pointSearch( + model, + meshData, + result, + currentElement, + visNodeXCoordinates[visNodeIndex], + visNodeYCoordinates[visNodeIndex], + basisFunctions + ); + + if (searchResult.inside) { + lastParentElement = currentElement; + visSolution[visNodeIndex] = searchResult.value; + found = true; + break; + } + } + } + } + + // Plot sizing parameters + let maxWindowWidth = Math.min(window.innerWidth, 700); + let maxX = Math.max(...nodesXCoordinates); + let maxY = Math.max(...nodesYCoordinates); + let aspectRatio = maxY / maxX; + let plotWidth = Math.min(maxWindowWidth, 600); + let plotHeight = plotWidth * aspectRatio; + + // Layout properties + let layout = { + title: `${plotType} plot (interpolated) - ${model.solverConfig}`, + width: plotWidth, + height: plotHeight, + xaxis: { title: "x" }, + yaxis: { title: "y" }, + margin: { l: 50, r: 50, t: 50, b: 50 }, + hovermode: "closest", + }; + + // Create the plot + let contourData = { + x: visNodeXCoordinates, + y: visNodeYCoordinates, + z: visSolution, + type: "contour", + line: { + smoothing: 0.85, + }, + contours: { + coloring: "heatmap", + showlabels: false, + }, + //colorscale: 'Viridis', + colorbar: { + title: "Solution", + }, + name: "Interpolated Solution Field", + }; + + Plotly.newPlot(plotDivId, [contourData], layout, { responsive: true }); + } +} + +/** + * Function to search if a point is inside an element and interpolate the solution + * @param {object} model - Object containing model properties + * @param {object} meshData - Object containing mesh data + * @param {object} result - Object containing solution vector and mesh information + * @param {number} currentElement - Index of the element to check + * @param {number} visNodeXCoordinate - X-coordinate of the point + * @param {number} visNodeYCoordinate - Y-coordinate of the point + * @param {object} basisFunctions - Instance of BasisFunctions class + * @returns {object} Object containing inside boolean and interpolated value + */ +function pointSearch(model, meshData, result, currentElement, visNodeXCoordinate, visNodeYCoordinate, basisFunctions) { + const { nodesXCoordinates, nodesYCoordinates } = result.nodesCoordinates; + const nodesPerElement = meshData.nop[currentElement].length; + + if (nodesPerElement === 4) { + // Linear quadrilateral element + let vertices = [ + [ + nodesXCoordinates[meshData.nop[currentElement][0] - 1], + nodesYCoordinates[meshData.nop[currentElement][0] - 1], + ], + [ + nodesXCoordinates[meshData.nop[currentElement][1] - 1], + nodesYCoordinates[meshData.nop[currentElement][1] - 1], + ], + [ + nodesXCoordinates[meshData.nop[currentElement][2] - 1], + nodesYCoordinates[meshData.nop[currentElement][2] - 1], + ], + [ + nodesXCoordinates[meshData.nop[currentElement][3] - 1], + nodesYCoordinates[meshData.nop[currentElement][3] - 1], + ], + ]; + const pointCheck = pointInsideQuadrilateral(visNodeXCoordinate, visNodeYCoordinate, vertices); + if (pointCheck.inside) { + return { + inside: true, + value: solutionInterpolation(model, meshData, result, currentElement, pointCheck.ksi, pointCheck.eta, basisFunctions), + }; + } + } else if (nodesPerElement === 9) { + // Quadratic quadrilateral element + let vertices = [ + [ + nodesXCoordinates[meshData.nop[currentElement][0] - 1], + nodesYCoordinates[meshData.nop[currentElement][0] - 1], + ], + [ + nodesXCoordinates[meshData.nop[currentElement][2] - 1], + nodesYCoordinates[meshData.nop[currentElement][2] - 1], + ], + [ + nodesXCoordinates[meshData.nop[currentElement][6] - 1], + nodesYCoordinates[meshData.nop[currentElement][6] - 1], + ], + [ + nodesXCoordinates[meshData.nop[currentElement][8] - 1], + nodesYCoordinates[meshData.nop[currentElement][8] - 1], + ], + ]; + const pointCheck = pointInsideQuadrilateral(visNodeXCoordinate, visNodeYCoordinate, vertices); + if (pointCheck.inside) { + return { + inside: true, + value: solutionInterpolation(model, meshData, result, currentElement, pointCheck.ksi, pointCheck.eta, basisFunctions), + }; + } + } // TODO: Add also triangular element cases + return { inside: false, value: null }; +} + +/** + * Function to interpolate the solution at a specific point (ksi, eta) within an element + * @param {object} model - Object containing model properties + * @param {object} meshData - Object containing mesh data + * @param {object} result - Object containing solution vector and mesh information + * @param {number} elementIndex - Index of the element containing the point + * @param {number} ksi - First natural coordinate (ksi) + * @param {number} eta - Second natural coordinate (eta) + * @param {object} basisFunctions - Instance of BasisFunctions class + * @returns {number} Interpolated solution value + */ +function solutionInterpolation(model, meshData, result, elementIndex, ksi, eta, basisFunctions) { + // Initialize FEA components + const solutionVector = result.solutionVector; + const nodesPerElement = meshData.nop[elementIndex].length; + + // Get basis functions for the current point + const basisFunctionsAndDerivatives = basisFunctions.getBasisFunctions(ksi, eta); + let basisFunction = basisFunctionsAndDerivatives.basisFunction; + + // Check if solutionVector is a nested array + let zData; + if (Array.isArray(solutionVector[0])) { + zData = solutionVector.map((val) => val[0]); + } else { + zData = solutionVector; + } + + // Interpolate solution + let solutionInterpolationValue = 0; + for (let localNodeIndex = 0; localNodeIndex < nodesPerElement; localNodeIndex++) { + solutionInterpolationValue += + zData[meshData.nop[elementIndex][localNodeIndex] - 1] * basisFunction[localNodeIndex]; + } + + return solutionInterpolationValue; +} + +/** + * Function to check if a point is inside a polygon using ray casting algorithm + * @param {number} x - X-coordinate of the point + * @param {number} y - Y-coordinate of the point + * @param {array} segments - Array of boundary segments + * @returns {boolean} True if the point is inside the polygon + */ +function pointInsidePolygon(x, y, segments) { + let inside = false; + for (let i = 0; i < segments.length; i++) { + const [[x1, y1], [x2, y2]] = segments[i]; + const intersect = y1 > y !== y2 > y && x < ((x2 - x1) * (y - y1)) / (y2 - y1) + x1; + if (intersect) inside = !inside; + } + return inside; +} diff --git a/src/workers/webgpuWorkerScript.js b/src/workers/webgpuWorkerScript.js index 78b4a7a..6f3ffb2 100644 --- a/src/workers/webgpuWorkerScript.js +++ b/src/workers/webgpuWorkerScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // External imports diff --git a/src/workers/workerScript.js b/src/workers/workerScript.js index 2e5ee8a..de129a8 100644 --- a/src/workers/workerScript.js +++ b/src/workers/workerScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // External imports diff --git a/src/workers/wrapperScript.js b/src/workers/wrapperScript.js index 77aa470..ef96b21 100644 --- a/src/workers/wrapperScript.js +++ b/src/workers/wrapperScript.js @@ -1,9 +1,10 @@ /** - * ════════════════════════════════════════════════════════════ - * FEAScript Library + * ════════════════════════════════════════════════════════════════ + * FEAScript Core Library * Lightweight Finite Element Simulation in JavaScript - * Version: 0.1.4 | https://feascript.com - * ════════════════════════════════════════════════════════════ + * Version: 0.2.0 (RC) | https://feascript.com + * MIT License © 2023–2025 FEAScript + * ════════════════════════════════════════════════════════════════ */ // External imports