const FLOW_N=240,CORONARY_FRACTION=.05,ARCH_FRACTION=.15,PA_LEFT_FRACTION=.45,SVC_FRACTION=.3333333333333333,LA_VOL_PER_UNIT=.25;function _deriv(e,a){const n=e.length,o=new Float32Array(n),c=a/n;for(let V=0;V<n;V++)o[V]=(e[(V+1)%n]-e[(V-1+n)%n])/(2*c);return o}function _integral(e,a){let n=0;for(const o of e)n+=o;return n*a/e.length}function _integralSign(e,a,n){let o=0;for(const c of e)(n>0?c>0:c<0)&&(o+=c);return o*a/e.length}function _scaleWhere(e,a,n){for(let o=0;o<e.length;o++)a(o)&&(e[o]*=n)}function _smooth(e,a,n){const o=e.length,c=n/a*o,V=Math.ceil(3*c),f=[];let u=0;for(let A=-V;A<=V;A++){const w=Math.exp(-.5*(A/c)*(A/c));f.push(w),u+=w}const d=new Float32Array(o);for(let A=0;A<o;A++){let w=0;for(let C=-V;C<=V;C++)w+=f[C+V]*e[(A+C+o)%o];d[A]=w/u}return d}const FLOW_SMOOTH_SEC=.02;function _sampleWig(e,a){const n=e.length,o=a*n,c=Math.min(n-1,Math.floor(o)),V=(c+1)%n;return e[c]+(e[V]-e[c])*(o-c)}function _regurg(e,a,n,o,c,V){const f=new Float32Array(e.length);let u=0;for(let A=0;A<e.length;A++){const w=getPhaseIndex(e[A]);n.includes(w)&&(f[A]=Math.sqrt(Math.max(0,o(e[A]))),u+=f[A])}const d=u>0?c/(u*a/e.length):0;for(let A=0;A<f.length;A++)f[A]*=V*d;return f}function buildFlowCurves(e,a=e.HR){const n=60/a,o=240,c=new Float32Array(o);for(let t=0;t<o;t++)c[t]=(t+.5)/o;const V=buildWiggersCurves(e,a),f=e.EDV-e.ESV,u=e.regurgFrac||0,d=f*(1-u),A=f*u,w=e.murmur&&e.murmur.kind,C=w==="MR",U=w==="AR",O={LV:t=>_sampleWig(V.LV,t),LA:t=>_sampleWig(V.LA,t),AO:t=>_sampleWig(V.AO,t),RA:t=>_sampleWig(V.RA,t)},L=new Float32Array(o);for(let t=0;t<o;t++)L[t]=e.EDV-ventricleContractionAt(c[t],e)*f;const m=_deriv(L,n),r={},T=C?_regurg(c,n,[1,2,3,4],t=>O.LV(t)-O.LA(t),A,-1):new Float32Array(o),E=U?_regurg(c,n,[4,5,6,0],t=>O.AO(t)-O.LV(t),A,-1):new Float32Array(o);r.AV=new Float32Array(o),r.MV=new Float32Array(o);for(let t=0;t<o;t++){const s=getPhaseIndex(c[t]),i=s>=1&&s<=3,_=s>=1&&s<=4;r.AV[t]=i?Math.max(0,-m[t]+T[t]):E[t],r.MV[t]=_?T[t]:Math.max(0,m[t]+E[t])}const I=_integralSign(r.AV,n,1),P=_integralSign(r.MV,n,1);I>0&&_scaleWhere(r.AV,t=>r.AV[t]>0,d/I),P>0&&_scaleWhere(r.MV,t=>r.MV[t]>0,d/P);const R=e.rvEDV,W=R-d,g=new Float32Array(o);for(let t=0;t<o;t++)g[t]=R-ventricleContractionAt(c[t],e)*(R-W);const S=_deriv(g,n);r.PV=new Float32Array(o),r.TV=new Float32Array(o);for(let t=0;t<o;t++){const s=getPhaseIndex(c[t]);s>=1&&s<=4?r.PV[t]=Math.max(0,-S[t]):r.TV[t]=Math.max(0,S[t])}const p=t=>{const s=new Float32Array(o);for(let i=0;i<o;i++)s[i]=t*(1+LA_VOL_PER_UNIT*atrialContractionAt(c[i]));return s},N=p(e.laVol),k=p(e.raVol),j=_deriv(N,n),q=_deriv(k,n);r.PULM_VEINS=new Float32Array(o),r.CAVAL=new Float32Array(o);for(let t=0;t<o;t++)r.PULM_VEINS[t]=j[t]+r.MV[t],r.CAVAL[t]=q[t]+r.TV[t];for(const t of["PULM_VEINS","CAVAL"]){const s=_integral(r[t],n);if(s>0){const i=d/s;for(let _=0;_<o;_++)r[t][_]*=i}}for(const t of["AV","MV","PV","TV","PULM_VEINS","CAVAL"])r[t]=_smooth(r[t],n,FLOW_SMOOTH_SEC);const G={AV:[2,3],PV:[2,3],MV:[5,6,0],TV:[5,6,0]};for(const[t,s]of Object.entries(G)){const i=r[t];for(let l=0;l<o;l++)i[l]>0&&!s.includes(getPhaseIndex(c[l]))&&(i[l]=0);const _=_integralSign(i,n,1);_>0&&_scaleWhere(i,l=>i[l]>0,d/_)}r.SVC=r.CAVAL.map(t=>t*SVC_FRACTION),r.IVC=r.CAVAL.map(t=>t*(1-SVC_FRACTION)),r.PV_EACH=r.PULM_VEINS.map(t=>t/4);const Q=.12,x=t=>{const s=new Float32Array(o),i=n/o;let _=0;for(let l=0;l<3;l++)for(let F=0;F<o;F++)_+=(t[F]-_)*i/Q,s[F]=_;return s};r.AO_ROOT=r.AV;const y=x(r.AV);r.AO_ARCH=y.map(t=>t*.15),r.AO_DESC=y.map(t=>t*(1-.15)),r.PA_ROOT=r.PV;const v=x(r.PV);r.PA_LEFT=v.map(t=>t*.45),r.PA_RIGHT=v.map(t=>t*(1-.45));const h=.05*d*a/60,M=t=>{const s=new Float32Array(o);let i=0;for(let l=0;l<o;l++)s[l]=Math.max(0,t(c[l])),i+=s[l];const _=i>0?o/i:0;for(let l=0;l<o;l++)s[l]*=_;return s},Y=M(t=>O.AO(t)-.9*O.LV(t)),B=M(t=>O.AO(t)-.25*O.LV(t)),K=M(t=>.3*O.AO(t)+O.LV(t));r.COR_LEFT=Y.map(t=>t*h*.7),r.COR_RIGHT=B.map(t=>t*h*.3),r.COR_VEIN=K.map(t=>t*h);const b={};for(const[t,s]of Object.entries(r))b[t]={fwd:+_integralSign(s,n,1).toFixed(1),back:+_integralSign(s,n,-1).toFixed(1)};const D={LV:L,RV:g,LA:N,RA:k},H={};for(const[t,s]of Object.entries(D))H[t]=s.reduce((i,_)=>Math.max(i,_),-1/0);return{period:n,n:o,ts:c,Q:r,V:D,Vmax:H,integrals:b,forwardSV:d,regurgVol:A,SV:f}}function _sampleCycle(e,a){const n=e.length,o=a*n-.5,c=Math.floor(o),V=o-c,f=e[(c%n+n)%n],u=e[((c+1)%n+n)%n];return f+(u-f)*V}function flowAt(e,a,n){const o=e.Q[a];return o?_sampleCycle(o,n):0}function volumeAt(e,a,n){const o=e.V[a];return o?_sampleCycle(o,n):0}function flowAudit(){const e=[];for(const a of Object.values(STATES)){const n=buildFlowCurves(a),o=n.integrals;e.push({state:a.id,forwardSV:+n.forwardSV.toFixed(1),regurgVol:+n.regurgVol.toFixed(1),AV_fwd:o.AV.fwd,AV_back:o.AV.back,MV_fwd:o.MV.fwd,MV_back:o.MV.back,PV_fwd:o.PV.fwd,TV_fwd:o.TV.fwd,pulmVeins:o.PULM_VEINS.fwd+o.PULM_VEINS.back,caval:o.CAVAL.fwd+o.CAVAL.back,aoDesc:+(o.AO_DESC.fwd+o.AO_DESC.back).toFixed(1),aoDescBack:o.AO_DESC.back,corLeft:+o.COR_LEFT.fwd.toFixed(1),corRight:+o.COR_RIGHT.fwd.toFixed(1)})}return e}Object.assign(window,{buildFlowCurves,flowAt,volumeAt,flowAudit,FLOW_N:240});
