From 2749df6dcb34ac672f2696637662e8c6ba0bcb79 Mon Sep 17 00:00:00 2001 From: Christopher Wipf <wipf@ligo.mit.edu> Date: Wed, 22 Aug 2018 18:47:56 -0700 Subject: [PATCH] quantum.py functions updated from matgwinc The matgwinc updates include a new shotradSignalRecycled(), and minor corrections to the previous code, which is still available as shotradSignalRecycledBnC(). shotradSignalRecycled() has been vectorized for good performance, with its two TF inversions pre-computed by sympy. --- gwinc/noise/quantum.py | 206 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 204 insertions(+), 2 deletions(-) diff --git a/gwinc/noise/quantum.py b/gwinc/noise/quantum.py index 6c0257e9..73f0112d 100644 --- a/gwinc/noise/quantum.py +++ b/gwinc/noise/quantum.py @@ -254,7 +254,209 @@ def shotrad(f, ifo): return n * ifo.gwinc.sinc_sqr +def compile_ARM_RES_TF(): + import sympy as sp + ID = sp.eye(2) + rITM, tArm, exp_2jOmegaL_c, K = sp.symbols('rITM tArm exp_2jOmegaL_c K') + ARM = tArm * exp_2jOmegaL_c * sp.Matrix([[1, 0], [-K, 1]]) + ARM_RES = (ID - rITM*ARM)**-1 + + subexprs, ARM_RES_expr = sp.cse(ARM_RES) + for expr in subexprs: + print(str(expr[0]), '=', str(expr[1])) + print('RES', '=', str(ARM_RES_expr[0]).replace('Matrix', 'np.array').replace(', 0]', ', np.zeros(nf)]')) + + +def compile_SEC_RES_TF(): + import sympy as sp + ID = sp.eye(2) + phi, exp_1jOmegal_c, tArm, exp_2jOmegaL_c, K, r00, r10, r11, R, T, rITM, tSR, rho = sp.symbols('phi exp_1jOmegal_c tArm exp_2jOmegaL_c K r00 r10 r11 R T rITM tSR rho') + SEr = sp.Matrix([[sp.cos(phi), sp.sin(phi)], [-sp.sin(phi), sp.cos(phi)]]) + SE = SEr * exp_1jOmegal_c + ARM = tArm * exp_2jOmegaL_c * sp.Matrix([[1, 0], [-K, 1]]) + ARM_RES = sp.Matrix([[r00, 0], [r10, r11]]) + rho_ARM = ARM_RES * ((R + T) * ARM - rITM * ID) + SEC = tSR * SE * rho_ARM * SE + SEC_RES = (ID + rho*SEC)**-1 + + subexprs, SEC_RES_expr = sp.cse(SEC_RES) + for expr in subexprs: + print(str(expr[0]), '=', str(expr[1])) + print('RES', '=', str(SEC_RES_expr[0]).replace('Matrix', 'np.array')) + + def shotradSignalRecycled(f, ifo): + """Quantum noise model for signal recycled IFO (see shotrad for more info) + + New version July 2016 by JH based on transfer function formalism + + coeff = frequency dependent overall noise coefficient (Nx1) + (not required anymore, but kept for compatibility with shotrad.m) + Mifo = IFO input-output relation for the AS port + Msig = signal transfer to the AS port + Mnoise = noise fields produced by losses in the IFO at the AS port + + """ + # f # Signal Freq. [Hz] + lambda_ = ifo.Laser.Wavelength # Laser Wavelength [m] + hbar = scipy.constants.hbar # Plancks Constant [Js] + c = scipy.constants.c # SOL [m/s] + omega_0 = 2*pi*c/lambda_ # Laser angular frequency [rads/s] + + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + L = ifo.Infrastructure.Length # Length of arm cavities [m] + l = ifo.Optics.SRM.CavityLength # SRC Length [m] + T = ifo.Optics.ITM.Transmittance # ITM Transmittance [Power] + m = ifo.Materials.MirrorMass # Mirror mass [kg] + + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + bsloss = ifo.Optics.BSLoss # BS Loss [Power] + mismatch = 1 - ifo.Optics.coupling # Mismatch + mismatch = mismatch + ifo.TCS.SRCloss # Mismatch + + # BSloss + mismatch has been incorporated into a SRC Loss + lambda_SR = 1 - (1 - mismatch) * (1 - bsloss) # SR cavity loss [Power] + + tau = sqrt(ifo.Optics.SRM.Transmittance) # SRM Transmittance [amplitude] + rho = sqrt(1 - tau**2) # SRM Reflectivity [amplitude] + + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + ds = ifo.Optics.SRM.Tunephase # SRC Detunning + phi = ds/2 + + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + lambda_arm = 1 - (1 - ifo.Optics.Loss)**2 * (1 - ifo.Optics.ETM.Transmittance) + + R = 1 - T - ifo.Optics.Loss # ITM Reflectivity [Power] + + P = ifo.gwinc.parm # use precomputed value + + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + nf = len(f) + + ID = np.array([[np.ones(nf), np.zeros(nf)], [np.zeros(nf), np.ones(nf)]]) + + # transfer matrices for dark port input and signal field + Mifo = zeros((2,2,nf), dtype=complex) + Msig = zeros((2,1,nf), dtype=complex) + + # transfer matrices for SEC and arm loss fields + Mp = zeros((2,2,nf), dtype=complex) + Mn = zeros((2,2,nf), dtype=complex) + + # SRC rotation matrix + SEr = np.array([[np.tile(cos(phi), nf), np.tile(sin(phi), nf)], + [np.tile(-sin(phi), nf), np.tile(cos(phi), nf)]]) + + # some precomputed parameters + tITM = sqrt(T) + rITM = sqrt(R) + + tArm = sqrt(1 - lambda_arm) + tSR = sqrt(1 - lambda_SR) + tSig = sqrt((1 - lambda_arm / 2) * (1 - lambda_SR / 2)) + RT_SRM = rho**2 + tau**2 + + lossArm = sqrt(lambda_arm) + lossSR = sqrt(lambda_SR) + + Omega = 2*pi*f # Signal angular frequency [rad/s] + h_SQL = sqrt(8 * hbar / (m * (Omega * L)**2)) # SQL Strain + K = 16 * P * omega_0 / (m * c**2 * Omega**2) + + # arm cavity + exp_2jOmegaL_c = exp(2j*Omega*L/c) + ARM = tArm * exp_2jOmegaL_c * np.array([[np.ones(nf), np.zeros(nf)], [-K, np.ones(nf)]]) + + # the following code is generated by compile_ARM_RES_TF() + # and is equivalent to the following: + # RES = zeros((2,2,nf), dtype=complex) + # RES = np.linalg.pinv(ID.transpose((2,0,1)) - rITM * ARM.transpose((2,0,1))).transpose((1,2,0)) + x0 = exp_2jOmegaL_c*rITM*tArm + x1 = -x0 + 1 + x2 = 1/x1 + RES = np.array([[x2, np.zeros(nf)], [-K*x0/x1**2, x2]]) + # end of generated code + + rho_ARM = getProdTF(RES, (R + T) * ARM - rITM * ID) + tau_ARM = tITM * RES + + # signal-extraction cavity + SE = SEr * exp(1j * Omega * l / c) + SEC = getProdTF(tSR * SE, getProdTF(rho_ARM, SE)) + + exp_1jOmegal_c = exp(1j*Omega*l/c) + r00 = RES[0,0,:] + r10 = RES[1,0,:] + r11 = RES[1,1,:] + + # the following code is generated by compile_SEC_RES_TF() + # and is equivalent to the following: + # RES = zeros((2,2,nf), dtype=complex) + # RES = np.linalg.pinv(ID.transpose((2,0,1)) + rho * SEC.transpose((2,0,1))).transpose((1,2,0)) + x0 = cos(phi) + x1 = exp_2jOmegaL_c*tArm*(R + T) + x2 = -rITM + x1 + x3 = exp_1jOmegal_c**2*r11*tSR*x2 + x4 = sin(phi) + x5 = exp_1jOmegal_c*r00*tSR*x2 + x6 = exp_1jOmegal_c*tSR*(-K*r11*x1 + r10*x2) + x7 = exp_1jOmegal_c*(x0*x6 - x4*x5) + x8 = rho*(x0**2*x3 + x4*x7) + 1 + x9 = x0*x3*x4 + x10 = exp_1jOmegal_c*(x0*x5 + x4*x6) + x11 = x10*x4 + x9 + x12 = x0*x7 - x9 + x13 = rho*(x0*x10 - x3*x4**2) + 1 + x14 = 1/(-rho**2*x11*x12 + x13*x8) + x15 = rho*x14 + RES = np.array([[x14*x8, -x11*x15], [-x12*x15, x13*x14]]) + # end of generated code + + rho_SEC = getProdTF(RES, RT_SRM * SEC + rho * ID) + tau_SEC = tau * getProdTF(RES, SE) + tau_SEC_ARM = getProdTF(tau_SEC, tau_ARM) + + # signal field + Msig = tSig * exp(1j * Omega * L / c) * \ + getProdTF(tau_SEC_ARM, np.array([[np.zeros(nf)], [sqrt(2 * K) / h_SQL]])) + + # dark-port input field + Mifo = rho_SEC + + # loss field from arm cavity + Mn = lossArm * tau_SEC_ARM + + # loss field from signal-extraction cavity + Mp = lossSR * tau_SEC + + # adapt to GWINC phase convention + Msig = Msig[[1, 0], :, :] + Msig[1, 0, :] = -Msig[1, 0, :] + + def adapt_to_gwinc(Mx): + My = zeros(Mx.shape, dtype=complex) + My[0, 0, :] = Mx[1, 1, :] + My[1, 1, :] = Mx[0, 0, :] + My[0, 1, :] = -Mx[1, 0, :] + My[1, 0, :] = -Mx[0, 1, :] + return My + + Mifo = adapt_to_gwinc(Mifo) + Mn = adapt_to_gwinc(Mn) + Mp = adapt_to_gwinc(Mp) + + # overall coefficient + coeff = 1 + + # put all loss fields together + Mnoise = np.hstack([Mn, Mp]) + + return coeff, Mifo, Msig, Mnoise + + +def shotradSignalRecycledBnC(f, ifo): """Quantum noise model for signal recycled IFO See shotrad for more info. @@ -342,7 +544,7 @@ def shotradSignalRecycled(f, ifo): 1/2*lambda_SR * ( sin(2*phi)+Kappa*sin(phi)**2) ) C21_L = tau**2 * ( (sin(2*phi)-Kappa*cos(phi)**2 ) + - 1/2*epsilon*cos(phi) * ( (3+exp_2jbeta )*Kappa*sin(phi) - 4*cos_beta**2*sin(phi) ) + + 1/2*epsilon*cos(phi) * ( (3+exp_2jbeta )*Kappa*cos(phi) - 4*cos_beta**2*sin(phi) ) + 1/2*lambda_SR * ( -sin(2*phi) + Kappa*cos(phi)**2) ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -381,7 +583,7 @@ def shotradSignalRecycled(f, ifo): 2*cos_beta*(invexp_1jbeta*cos(phi)-rho*exp_1jbeta*(cos(phi)+Kappa*sin(phi)))) N22 = -sqrt(2*epsilon)*tau*(-invexp_1jbeta+rho*exp_1jbeta)*cos_beta*cos(phi) N12 = -sqrt(2*epsilon)*tau*(invexp_1jbeta+rho*exp_1jbeta)*cos_beta*sin(phi); - N21 = sqrt(2*epsilon)*tau*(-Kappa*(1+rho)*cos(phi)+ + N21 = sqrt(epsilon/2)*tau*(-Kappa*(1+rho)*cos(phi)+ 2*cos_beta*(invexp_1jbeta+rho*exp_1jbeta)*cos_beta*sin(phi)) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- GitLab