|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +""" |
| 3 | +Created on Thu Feb 11 15:50:08 2016 |
| 4 | +
|
| 5 | +@author: jklymak |
| 6 | +""" |
| 7 | +import numpy as np |
| 8 | +from vertmodes import vertModes |
| 9 | +import logging |
| 10 | + |
| 11 | +def SolveRefl(k=0.,f =1.06e-4,omega=1.45e-4+1j*1e-6,wall=True,H=[],x=[],J=30,Nsq0=[],z0=[], |
| 12 | + Incoming=True,Forcing=[]): |
| 13 | + '''x,z,H,P=SolveRefl(k=0.) |
| 14 | + This one does variable Nsq |
| 15 | + ''' |
| 16 | + log=logging.getLogger('SolveRefl') |
| 17 | + inv = np.linalg.inv |
| 18 | + ## Model Params: |
| 19 | + k00=k |
| 20 | + dz = 1./(J+1) |
| 21 | + usebcs = True |
| 22 | + z = np.linspace(-1.,0.,J+1) |
| 23 | + dz = z[1]-z[0] |
| 24 | + #z = z[:-1]+0.5*dz |
| 25 | + zmid = z[:-1]+0.5*dz |
| 26 | + |
| 27 | + #lamsq = (np.real(omega)**2-f**2)/(Nsq0 - np.real(omega)**2)+0*z |
| 28 | + I = len(x) |
| 29 | + dx = x[2]-x[1] |
| 30 | + |
| 31 | + H[-2]=H[-1]; |
| 32 | + H[1]=H[0] |
| 33 | + Hx = np.gradient(H,dx);Hxx = np.gradient(Hx,dx) |
| 34 | + # Just calculate Nsq once... |
| 35 | + |
| 36 | + Z0 = z[:,np.newaxis]*H[np.newaxis,:] |
| 37 | + Nsq = 0.*Z0 |
| 38 | + for a in range(len(H)): |
| 39 | + Nsq[:,a]=np.interp(Z0[:,a],z0,Nsq0) |
| 40 | + dNsqdz=np.diff(Nsq,axis=0)/dz/H[np.newaxis,:] |
| 41 | + # now we want it on teh midpoints... |
| 42 | + Z0 = zmid[:,np.newaxis]*H[np.newaxis,:] |
| 43 | + Nsq = 0.*Z0 |
| 44 | + for a in range(len(H)): |
| 45 | + Nsq[:,a]=np.interp(Z0[:,a],z0,Nsq0) |
| 46 | + |
| 47 | + N2 = np.interp(zmid*H[0],z0,Nsq0) |
| 48 | + psi,phi,ce,zpsi=vertModes(N2[::-1],dz*H[0]) |
| 49 | + log.debug(ce[:10]) |
| 50 | + #flip back because our matrices are from the bottom |
| 51 | + psi = psi[::-1,:]*np.sqrt(dz*H[0]) |
| 52 | + |
| 53 | + Z = np.diag(zmid,k=0)+0.*1j;eye = np.eye(J)+0.*1j |
| 54 | + ## To get started, we need P01, P02, and E and Ep... |
| 55 | + if 1: |
| 56 | + Amp=1.+1j*0. |
| 57 | + #pin1=pin1/np.max(np.abs(pin1)) |
| 58 | + # Hmmm, OK this is hydrostatic. What should it be? |
| 59 | + k1 = (np.real(omega)**2 - f**2)/ce[0]**2 -k00**2 |
| 60 | + log.debug(np.pi*2./k1/1.e3,ce[:10]) |
| 61 | + if k1<0: |
| 62 | + k1 = -1j*np.sqrt(-k1) # forcingd decays to left e^{kx} |
| 63 | + else: |
| 64 | + k1 = np.sqrt(k1) # wave is cominhg from right e^{j kx} |
| 65 | + pin1 = Amp*psi[:,0]/psi[0,0]*np.exp(1j*k1*x[0]) |
| 66 | + pin2 = pin1 + 1j*k1*dx |
| 67 | + log.debug(psi[0,0],pin1[0],pin2[0]) |
| 68 | + pin2 = Amp*psi[:,0]/psi[0,0]*np.exp(1j*k1*x[1]) # = pin1 + dx *dPin/dx |
| 69 | + log.debug(pin2[0]) |
| 70 | + if not(Incoming): |
| 71 | + pin1=0.*pin1 |
| 72 | + pin2=0.*pin2 |
| 73 | + |
| 74 | + # LHS radiating boundnary condition. Note that for k00 neq 0 |
| 75 | + # k^2 can be negative, which implies a leftward decay... |
| 76 | + nmodes = J-4 |
| 77 | + E1 = psi[:,0:nmodes]+0.*1j |
| 78 | + K = np.zeros((nmodes,nmodes))*1j |
| 79 | + for j in range(nmodes): |
| 80 | + kk = (np.real(omega)**2 - f**2)/ce[j]**2 - k00**2 |
| 81 | + if kk<0: |
| 82 | + kk = -1j*np.sqrt(-kk) # decay to left e^(kx) |
| 83 | + else: |
| 84 | + kk = -np.sqrt(kk) # leftward! e^(-jkx) |
| 85 | + K[j,j] = 1j*kk*dx |
| 86 | + log.debug('lam',np.pi*2./K[0,0]/1e3*dx) |
| 87 | + alpha=[] |
| 88 | + beta=[] |
| 89 | + for k in range(I+1): |
| 90 | + alpha.append(np.zeros((J,J))*1j) |
| 91 | + beta.append(np.zeros((J))*1j) |
| 92 | + log.debug(E1.dot(E1.transpose().conj())) |
| 93 | + ee = (E1.dot(K)).dot(E1.transpose().conj()) |
| 94 | + alpha[0]=inv(eye+ee) |
| 95 | + beta[0]=pin1-(inv(eye+ee)).dot(pin2) |
| 96 | + |
| 97 | + P1 = np.zeros((J,J)); |
| 98 | + P2 = np.zeros((J,J)); |
| 99 | + for j in range(1,J-1): |
| 100 | + P1[j,j-1]=-1;P1[j,j+1]=1; |
| 101 | + P2[j,j-1]=1;P2[j,j]=-2;P2[j,j+1]=1; |
| 102 | + P1[0,1]=1;P1[J-1,J-2]=-1; |
| 103 | + P2[0,0]=-2; P2[0,1]=1;P2[J-1,J-2]=1;P2[J-1,J-1]=-2; |
| 104 | + ## So, that eliminates the error from the LHS.... |
| 105 | + dxsq=dx**2 |
| 106 | + for i in range(1,I-1): |
| 107 | + lamsq = (np.real(omega)**2-f**2)/(Nsq[:,i] - 0.*np.real(omega)**2) |
| 108 | + gamsq = lamsq/(Nsq[:,i] - 0.*np.real(omega)**2) |
| 109 | + lamsq = np.diag(lamsq,k=0)+1j*0. |
| 110 | + gamsq = np.diag(gamsq,k=0)+1j*0. |
| 111 | + G2 = -2*Hx[i]/H[i]*Z +0*1j # G2 1/m |
| 112 | + G3 = -(Hxx[i]*H[i]-2*Hx[i]**2)/H[i]**2*Z + 0*1j # 1/m^2 |
| 113 | + G3 = G3 + gamsq*dNsqdz[:,i]/H[i] |
| 114 | + G4 = (Hx[i]**2*Z.dot(Z)-lamsq)/H[i]**2 +0*1j # G4 1/m^2 |
| 115 | + # get A, B , C , D |
| 116 | + |
| 117 | + D = np.zeros((J))*1j ## This needs to be set to something if you want internal forcing (versus an incoming wave) |
| 118 | + |
| 119 | + if not(Incoming): |
| 120 | + if len(Forcing)==0: |
| 121 | + if np.abs(x[i]-50e3)<1000000.e3: |
| 122 | + D[2*J/4:3*J/4]+=1e-9/H[i] |
| 123 | + else: |
| 124 | + D = Forcing[:,i] |
| 125 | + A = eye*1./dxsq - G2.dot(P1)/4./dx/dz +0.*1j #1/m^2 |
| 126 | + B = -eye*(2./dxsq + k00**2) + G3.dot(P1)/2./dz +G4.dot(P2)/dz**2 +0.*1j # 1/m^2 + 1/m^2 + 1/m^2 |
| 127 | + C = eye*1./dxsq + G2.dot(P1)/4./dx/dz +0.*1j # 1/m^2 |
| 128 | + if True: # use BC |
| 129 | + b1 = (lamsq[0,0] + zmid[0]*Hx[i]**2)/H[i]/H[i]; # 1/m^2 |
| 130 | + b2=-Hx[i]/H[i]; # 1/m |
| 131 | + b3 = f*k00/omega*Hx[i]/H[i]; # 1/m^2 |
| 132 | + |
| 133 | + # Note that this gives proper units to the BCs |
| 134 | + |
| 135 | + A[0,0]=-b2/2./dx; A[0,1]=0; # seafloor |
| 136 | + A[J-1,J-1]=0.;A[J-1,J-2]=0. # sea surface... |
| 137 | + |
| 138 | + B[0,0]= -b1/dz + b3; B[0,1]= +b1/dz |
| 139 | + B[J-1,J-1]= lamsq[-1,-1]/H[i]**2/dz |
| 140 | + B[J-1,J-2]=-lamsq[-1,-1]/H[i]**2/dz |
| 141 | + |
| 142 | + C[0,0]=b2/2./dx;C[0,1]=0; |
| 143 | + #C[0,0] += 1./dxsq; |
| 144 | + C[J-1,J-1]=0.;C[J-1,J-2]=0.; |
| 145 | + #C[J-1,J-1]+= 1./dxsq |
| 146 | + bb = inv(A.dot(alpha[i-1])+B) |
| 147 | + alpha[i]=-bb.dot(C) |
| 148 | + beta[i]=bb.dot(D)-(bb.dot(A.dot(beta[i-1]))) |
| 149 | + |
| 150 | + # get P[I-1] |
| 151 | + P = np.zeros((J,I))+0.0*1j |
| 152 | + |
| 153 | + if wall: |
| 154 | + log.debug("Wall") |
| 155 | + P[:,I-1] = inv(eye*(1.-f*k00*dx/omega)-alpha[I-2]).dot(beta[I-2]) |
| 156 | + else: # radiating... |
| 157 | + N2 = np.interp(zmid*H[-1],z0,Nsq0) |
| 158 | + |
| 159 | + psi,phi,ce,zphi=vertModes(N2[::-1],dz*H[-1]) |
| 160 | + psi = psi[::-1,:]*np.sqrt(dz*H[-1]) |
| 161 | + |
| 162 | + E2 = psi[:,0:nmodes]+0.*1j |
| 163 | + K = np.zeros((nmodes,nmodes))*1j |
| 164 | + for j in range(nmodes): |
| 165 | + kk = (np.real(omega)**2 - f**2)/ce[j]**2 - k00**2 |
| 166 | + if j==0: |
| 167 | + log.debug("kk[0]",kk) |
| 168 | + if kk<0: |
| 169 | + kk = 1j*np.sqrt(-kk) # decay to right e^(-kx) |
| 170 | + else: |
| 171 | + kk = np.sqrt(kk) # rightward! e^(jkx) |
| 172 | + K[j,j] = 1j*kk*dx |
| 173 | + E2[:,j]=E2[:,j]*np.exp(1j*kk*x[-1]) |
| 174 | + E2d=E2.dot(K) |
| 175 | + E2inv = E2.transpose().conj() |
| 176 | + P[:,I-1]= inv(eye-alpha[I-2]-E2d.dot(E2inv)).dot(beta[I-2]) |
| 177 | + |
| 178 | + # back iterate to get P |
| 179 | + for i in range(I-2,-1,-1): |
| 180 | + P[:,i] = alpha[i].dot(P[:,i+1])+beta[i] |
| 181 | + |
| 182 | + |
| 183 | + return x,zmid,H,P,[E1,np.diag(K)] |
| 184 | + |
0 commit comments