From 5f230ef174264f9c3996b148e32f01632d20ad1d Mon Sep 17 00:00:00 2001 From: Jameson Graef Rollins <jrollins@finestructure.net> Date: Thu, 19 Sep 2019 23:56:16 -0700 Subject: [PATCH] coating noise simplification new coating_brownian() and coating_thermooptic() functions for calculating coating thermal noise spectrum for a single optic. ifo CoatingBrownian and CoatingThermoOptic Noise classes modified to handle specific case of Fabry-Perot Michelson. --- gwinc/ifo/noises.py | 24 +- gwinc/noise/coatingthermal.py | 473 +++++++++++++++------------------- gwinc/precomp.py | 4 +- 3 files changed, 225 insertions(+), 276 deletions(-) diff --git a/gwinc/ifo/noises.py b/gwinc/ifo/noises.py index 37a7c2f8..dacb91c8 100644 --- a/gwinc/ifo/noises.py +++ b/gwinc/ifo/noises.py @@ -114,7 +114,17 @@ class CoatingBrownian(nb.Noise): ) def calc(self): - return noise.coatingthermal.coatbrownian(self.freq, self.ifo) + wavelength = self.ifo.Laser.Wavelength + materials = self.ifo.Materials + wBeam_ITM = self.ifo.Optics.ITM.BeamRadius + wBeam_ETM = self.ifo.Optics.ETM.BeamRadius + dOpt_ITM = self.ifo.Optics.ITM.CoatLayerOpticalThickness + dOpt_ETM = self.ifo.Optics.ETM.CoatLayerOpticalThickness + nITM = noise.coatingthermal.coating_brownian( + self.freq, materials, wavelength, wBeam_ITM, dOpt_ITM) + nETM = noise.coatingthermal.coating_brownian( + self.freq, materials, wavelength, wBeam_ETM, dOpt_ETM) + return (nITM + nETM) * 2 * self.ifo.gwinc.dhdl_sqr class CoatingThermoOptic(nb.Noise): @@ -128,7 +138,17 @@ class CoatingThermoOptic(nb.Noise): ) def calc(self): - return noise.coatingthermal.thermooptic(self.freq, self.ifo) + wavelength = self.ifo.Laser.Wavelength + materials = self.ifo.Materials + wBeam_ITM = self.ifo.Optics.ITM.BeamRadius + wBeam_ETM = self.ifo.Optics.ETM.BeamRadius + dOpt_ITM = self.ifo.Optics.ITM.CoatLayerOpticalThickness + dOpt_ETM = self.ifo.Optics.ETM.CoatLayerOpticalThickness + nITM, junk1, junk2, junk3 = noise.coatingthermal.coating_thermooptic( + self.freq, materials, wavelength, wBeam_ITM, dOpt_ITM[:]) + nETM, junk1, junk2, junk3 = noise.coatingthermal.coating_thermooptic( + self.freq, materials, wavelength, wBeam_ETM, dOpt_ETM[:]) + return (nITM + nETM) * 2 * self.ifo.gwinc.dhdl_sqr class ITMThermoRefractive(nb.Noise): diff --git a/gwinc/noise/coatingthermal.py b/gwinc/noise/coatingthermal.py index 1d6d2878..29e641e5 100644 --- a/gwinc/noise/coatingthermal.py +++ b/gwinc/noise/coatingthermal.py @@ -1,66 +1,41 @@ +'''Functions to calculate coating thermal noise + +''' from __future__ import division, print_function -import scipy.special import numpy as np -from numpy import pi, sum, zeros, exp, real, imag, sqrt, sin, cos, sinh, cosh, polyfit, roots, max, min, ceil, log +from numpy import pi, sum, zeros, exp, real, imag, sqrt, sin, cos, sinh, cosh, polyfit, roots, min, ceil, log from .. import const from ..const import BESSEL_ZEROS as zeta from ..const import J0M as j0m -def coatbrownian(f, ifo): - """Optical coating Brownian thermal noise - - Returns strain noise power spectrum in 1 / Hz - - Added by G Harry 8/3/02 from work by Nakagawa, Gretarsson, et al. - Expanded to reduce approximation, GMH 8/03 - Modified to return strain noise, PF 4/07 - Modified to accept coating with non-quater-wave layers, mevans 25 Apr 2008 - - """ - Length = ifo.Infrastructure.Length - wBeam_ITM = ifo.Optics.ITM.BeamRadius - wBeam_ETM = ifo.Optics.ETM.BeamRadius - dOpt_ITM = ifo.Optics.ITM.CoatLayerOpticalThickness - dOpt_ETM = ifo.Optics.ETM.CoatLayerOpticalThickness - - # compute Brownian noise for specified coating structure - SbrITM = getCoatBrownian(f, ifo, wBeam_ITM, dOpt_ITM) - SbrETM = getCoatBrownian(f, ifo, wBeam_ETM, dOpt_ETM) - - n = 2 * (SbrITM + SbrETM) * ifo.gwinc.dhdl_sqr - - return n +def coating_brownian(f, materials, wavelength, wBeam, dOpt): + """Optical coating Brownian thermal displacement noise spectrum - -def getCoatBrownian(f, ifo, wBeam, dOpt): - """Coating brownian noise for a given collection of coating layers + :f: frequency array in Hz + :materials: gwinc optic materials structure + :wavelength: laser wavelength + :wBeam: beam radius (at 1 / e^2 power) + :dOpt: coating layer thickness array (Nlayer x 1) The layers are assumed to be alernating low-n high-n layers, with low-n first. - f = frequency vector in Hz - ifo = parameter struct from IFOmodel.m - - opticName = name of the Optic struct to use for wBeam and dOpt - wBeam = ifoArg.Optics.(opticName).BeamRadius - dOpt = ifoArg.Optics.(opticName).CoatLayerOpticalThickness - - wBeam = beam radius (at 1 / e^2 power) - dOpt = coating layer thickness vector (Nlayer x 1) - = the optical thickness, normalized by lambda, of each coating layer. + :returns: displacement noise power spectrum at :f: - SbrZ = Brownian noise spectra for one mirror in m^2 / Hz + Added by G Harry 8/3/02 from work by Nakagawa, Gretarsson, et al. + Expanded to reduce approximation, GMH 8/03 + Modified to return strain noise, PF 4/07 + Modified to accept coating with non-quater-wave layers, mevans 25 Apr 2008 """ # extract substructures - sub = ifo.Materials.Substrate - coat = ifo.Materials.Coating + sub = materials.Substrate + coat = materials.Coating # Constants kBT = const.kB * sub.Temp - lambda_ = ifo.Laser.Wavelength # substrate properties Ysub = sub.MirrorY # Young's Modulous @@ -101,14 +76,14 @@ def getCoatBrownian(f, ifo, wBeam, dOpt): phiN[1::2] = phihighn # geometrical thickness of each layer and total - dGeo = lambda_ * np.asarray(dOpt) / nN - dCoat = sum(dGeo) + dGeo = wavelength * np.asarray(dOpt) / nN + #dCoat = sum(dGeo) ################################### # Brownian ################################### # coating reflectivity - dcdp = getCoatRefl(ifo, dOpt)[1] + dcdp = getCoatRefl(materials, dOpt)[1] # Z-dir (1 => away from the substrate, -1 => into the substrate) zdir = -1 @@ -132,139 +107,114 @@ def getCoatBrownian(f, ifo, wBeam, dOpt): else: SbrZ = (4 * kBT / (pi * wBeam**2 * w)) * \ (1 - pratsub - 2 * pratsub**2) / Ysub - - SbrZ = SbrZ * (sum(dGeo[::2] * brLayer[::2] * phiN[::2]) * (f / 100)**(coat.Philown_slope) + - sum(dGeo[1::2] * brLayer[1::2] * phiN[1::2]) * (f / 100)**(coat.Phihighn_slope)) + SbrZ *= (sum(dGeo[::2] * brLayer[::2] * phiN[::2]) * (f / 100)**(coat.Philown_slope) + + sum(dGeo[1::2] * brLayer[1::2] * phiN[1::2]) * (f / 100)**(coat.Phihighn_slope)) # for the record: evaluate summation in eq 1 of PhysRevD.91.042002 # normalized by total coating thickness to make it unitless - cCoat = sum(dGeo * brLayer * phiN) / dCoat + #cCoat = sum(dGeo * brLayer * phiN) / dCoat return SbrZ -def thermooptic(f, ifo): - """Thermoelastic and thermorefractive fluctuations in the mirror dielectric coating - - Returns strain noise power spectrum in 1 / Hz. +def coating_thermooptic(f, materials, wavelength, wBeam, dOpt): + """Optical coating thermo-optic displacement noise spectrum - Added by G Harry 8/27/03 from work by Fejer, Rowan, Braginsky, et al - thermoelastic and thermorefractive effects combined coherently in 2006 + :f: frequency array in Hz + :materials: gwinc optic materials structure + :wavelength: laser wavelength + :wBeam: beam radius (at 1 / e^2 power) + :dOpt: coating layer thickness array (Nlayer x 1) - Reduced approximations and combined TE and TR - effects with correct sign, mevans 25 Apr 2008 - - """ - Length = ifo.Infrastructure.Length - wBeam_ITM = ifo.Optics.ITM.BeamRadius - wBeam_ETM = ifo.Optics.ETM.BeamRadius - dOpt_ITM = ifo.Optics.ITM.CoatLayerOpticalThickness - dOpt_ETM = ifo.Optics.ETM.CoatLayerOpticalThickness - - # compute ThermoOptic noise for specified coating structure - StoITM, junk1, junk2, junk3 = getCoatThermoOptic(f, ifo, wBeam_ITM, dOpt_ITM[:]) - StoETM, junk1, junk2, junk3 = getCoatThermoOptic(f, ifo, wBeam_ETM, dOpt_ETM[:]) - - n = 2 * (StoITM + StoETM) * ifo.gwinc.dhdl_sqr - - return n - - -def getCoatThermoOptic(f, ifo, wBeam, dOpt): - """Power spectra of coating thermo-optic noise for a single optic - - f = frequency vector in Hz - ifo = parameter struct from IFOmodel.m - opticName = name of the Optic struct to use for wBeam and dOpt - wBeam = ifoArg.Optics.(opticName).BeamRadius - dOpt = ifoArg.Optics.(opticName).CoatLayerOpticalThickness - - wBeam = beam radius (at 1 / e^2 power) - dOpt = optical thickness / lambda of each layer - = geometrical thickness * refractive index / lambda - - StoZ = power spectra of apparent mirror position in m^2 / Hz - SteZ = thermo-elastic componenet of StoZ - StrZ = thermo-refractive componenet of StoZ - T = coating power transmission, made available as a cross-check + :returns: tuple of: + StoZ = displacement noise power spectrum at :f: + SteZ = thermo-optic component of StoZ + StrZ = thermo-refractive component of StoZ + T = coating power transmission """ # compute coefficients - dTO, dTR, dTE, T, junk = getCoatTOPos(ifo, wBeam, dOpt) + dTO, dTR, dTE, T, junk = getCoatTOPos(materials, wavelength, wBeam, dOpt) # compute correction factors - gTO = getCoatThickCorr(f, ifo, dOpt, dTE, dTR) - gTE = getCoatThickCorr(f, ifo, dOpt, dTE, 0) - gTR = getCoatThickCorr(f, ifo, dOpt, 0, dTR) + gTO = getCoatThickCorr(f, materials, wavelength, dOpt, dTE, dTR) + gTE = getCoatThickCorr(f, materials, wavelength, dOpt, dTE, 0) + gTR = getCoatThickCorr(f, materials, wavelength, dOpt, 0, dTR) # compute thermal source spectrum - SsurfT, junk = getCoatThermal(f, ifo, wBeam) + SsurfT, junk = getCoatThermal(f, materials, wBeam) StoZ = SsurfT * gTO * dTO**2 SteZ = SsurfT * gTE * dTE**2 StrZ = SsurfT * gTR * dTR**2 + return (StoZ, SteZ, StrZ, T) -def getCoatTOPos(ifo, wBeam, dOpt): +def getCoatTOPos(materials, wavelength, wBeam, dOpt): """Mirror position derivative wrt thermal fluctuations - - ifo = parameter struct from IFOmodel.m - opticName = name of the Optic struct to use for wBeam and dOpt - wBeam = ifoArg.Optics.(opticName).BeamRadius - dOpt = ifoArg.Optics.(opticName).CoatLayerOpticalThickness - wBeam = beam radius, for finite mirror correction (at 1 / e^2 power) - dOpt = optical thickness / lambda of each layer - = geometrical thickness * refractive index / lambda + :materials: gwinc optic materials structure + :wavelength: laser wavelength + :wBeam: beam radius (at 1 / e^2 power) + :dOpt: coating layer thickness array (Nlayer x 1) + :returns: tuple of: dTO = total thermo-optic dz/dT dTR = thermo-refractive dz/dT dTE = thermo-elastic dz/dT + T = coating power transmission + R = coating power reflection - compute thermal fluctuations with getCoatThermal - (see also T080101) + Compute thermal fluctuations with getCoatThermal. + + See LIGO-T080101. """ - # parameters - lambda_ = ifo.Laser.Wavelength - nS = ifo.Materials.Substrate.RefractiveIndex - + # parameters + nS = materials.Substrate.RefractiveIndex + # compute refractive index, effective alpha and beta - nLayer, aLayer, bLayer, dLayer, sLayer = getCoatLayers(ifo, dOpt) + nLayer, aLayer, bLayer, dLayer, sLayer = getCoatLayers(materials, wavelength, dOpt) # compute coating average parameters - dc, Cc, Kc, aSub = getCoatAvg(ifo, dOpt) - + dc, Cc, Kc, aSub = getCoatAvg(materials, wavelength, dOpt) + # compute reflectivity and parameters dphi_dT, dphi_TE, dphi_TR, rCoat = getCoatTOPhase(1, nS, nLayer, dOpt, aLayer, bLayer, sLayer) R = abs(rCoat)**2 T = 1 - R - + # for debugging #disp(sprintf('R = %.3f, T = %.0f ppm', R, 1e6 * T)) - + # convert from phase to meters, subtracting substrate - dTR = dphi_TR * lambda_ / (4 * pi) - dTE = dphi_TE * lambda_ / (4 * pi) - aSub * dc + dTR = dphi_TR * wavelength / (4 * pi) + dTE = dphi_TE * wavelength / (4 * pi) - aSub * dc # mirror finite size correction - Cfsm = getCoatFiniteCorr(ifo, wBeam, dOpt) + Cfsm = getCoatFiniteCorr(materials, wavelength, wBeam, dOpt) dTE = dTE * Cfsm - + # add TE and TR effects (sign is already included) dTO = dTE + dTR - + return dTO, dTR, dTE, T, R -def getCoatThickCorr(f, ifo, dOpt, dTE, dTR): +def getCoatThickCorr(f, materials, wavelength, dOpt, dTE, dTR): """Finite coating thickness correction - Uses correction factor from T080101, "Thick Coating Correction" - (Evans). + :f: frequency array in Hz + :materials: gwinc optic materials structure + :wavelength: laser wavelength + :wBeam: beam radius (at 1 / e^2 power) + :dOpt: coating layer thickness array (Nlayer x 1) + + Uses correction factor from LIGO-T080101, "Thick Coating + Correction" (Evans). - (see getCoatThermoOptic for example usage) + See getCoatThermoOptic for example usage. """ ############################################## @@ -277,28 +227,28 @@ def getCoatThickCorr(f, ifo, dOpt, dTE, dTR): # gTC = 1 - xi * (R - 1 / (3 * R)); # parameter extraction - pS = ifo.Materials.Substrate + pS = materials.Substrate Cs = pS.MassCM * pS.MassDensity Ks = pS.MassKappa - + # compute coating average parameters - dc, Cc, Kc, junk = getCoatAvg(ifo, dOpt) - + dc, Cc, Kc, junk = getCoatAvg(materials, wavelength, dOpt) + # R and xi (from T080101, Thick Coating Correction) w = 2 * pi * f R = sqrt(Cc * Kc / (Cs * Ks)) xi = dc * sqrt(2 * w * Cc / Kc) - + # trig functions of xi s = sin(xi) c = cos(xi) sh = sinh(xi) ch = cosh(xi) - + # pR and pE (dTR = -\bar{\beta} lambda, dTE = \Delta \bar{\alpha} d) pR = dTR / (dTR + dTE) pE = dTE / (dTR + dTE) - + # various parts of gTC g0 = 2 * (sh - s) + 2 * R * (ch - c) g1 = 8 * sin(xi / 2) * (R * cosh(xi / 2) + sinh(xi / 2)) @@ -307,51 +257,47 @@ def getCoatThickCorr(f, ifo, dOpt, dTE, dTR): # and finally, the correction factor gTC = (pE**2 * g0 + pE * pR * xi * g1 + pR**2 * xi**2 * g2) / (R * xi**2 * gD) + return gTC -def getCoatThermal(f, ifo, wBeam): +def getCoatThermal(f, materials, wBeam): """Thermal noise spectra for a surface layer - f = frequency vector in Hz - ifo = parameter struct from IFOmodel.m - - wBeam = beam radius (at 1 / e^2 power) - = usually ifo.Optics.ITM.BeamRadius or ifo.Optics.ETM.BeamRadius + :f: frequency array in Hz + :materials: gwinc optic material structure + :wBeam: beam radius (at 1 / e^2 power) + :returns: tuple of: SsurfT = power spectra of thermal fluctuations in K^2 / Hz rdel = thermal diffusion length at each frequency in m """ - # use substrate temperature - subTemp = ifo.Materials.Substrate.Temp - - kBT2 = const.kB * subTemp**2 - - pS = ifo.Materials.Substrate + pS = materials.Substrate C_S = pS.MassCM * pS.MassDensity K_S = pS.MassKappa + kBT2 = const.kB * pS.Temp**2 # omega w = 2 * pi * f - + # thermal diffusion length rdel = sqrt(2 * K_S / (C_S * w)) - + # noise equation SsurfT = 4 * kBT2 / (pi * w * C_S * rdel * wBeam**2) + return SsurfT, rdel -def getCoatLayers(ifo, dOpt): +def getCoatLayers(materials, wavelength, dOpt): """Layer vectors for refractive index, effective alpha and beta and geometrical thickness - (see getCoatTOPos for example usage) - - ifo = parameter struct from IFOmodel.m - dOpt = optical thickness / lambda of each layer - = geometrical thickness * refractive index / lambda + :materials: gwinc optic materials structure + :wavelength: laser wavelength + :dOpt: coating layer thickness array (Nlayer x 1) + :returns: tuple of: nLayer = refractive index of each layer, ordered input to output (N x 1) aLayer = change in geometrical thickness with temperature = the effective thermal expansion coeffient of the coating layer @@ -363,35 +309,32 @@ def getCoatLayers(ifo, dOpt): """ # coating parameters - lambda_ = ifo.Laser.Wavelength - - pS = ifo.Materials.Substrate - pC = ifo.Materials.Coating - + pS = materials.Substrate + pC = materials.Coating + Y_S = pS.MirrorY sigS = pS.MirrorSigma - + alphaL = pC.Alphalown betaL = pC.Betalown Y_L = pC.Ylown sigL = pC.Sigmalown nL = pC.Indexlown - + alphaH = pC.Alphahighn betaH = pC.Betahighn Y_H = pC.Yhighn sigH = pC.Sigmahighn nH = pC.Indexhighn - + Nlayer = len(dOpt) - + # compute effective alpha def getExpansionRatio(Y_C, sigC, Y_S, sigS): ############################################## # Y_C and sigC are for the coating material (can also be substrate) # Y_S and sigS are for the substrate material # - ce = ((1 + sigS) / (1 - sigC)) \ * ( ((1 + sigC) / (1 + sigS)) + (1 - 2 * sigS) * Y_C / Y_S ) return ce @@ -399,7 +342,7 @@ def getCoatLayers(ifo, dOpt): aLayer = zeros(Nlayer) aLayer[::2] = alphaL * getExpansionRatio(Y_L, sigL, Y_S, sigS) aLayer[1::2] = alphaH * getExpansionRatio(Y_H, sigH, Y_S, sigS) - + # and beta bLayer = zeros(Nlayer) bLayer[::2] = betaL @@ -409,9 +352,9 @@ def getCoatLayers(ifo, dOpt): nLayer = zeros(Nlayer) nLayer[::2] = nL nLayer[1::2] = nH - + # and geometrical thickness - dLayer = lambda_ * np.asarray(dOpt) / nLayer + dLayer = wavelength * np.asarray(dOpt) / nLayer # and sigma correction sLayer = zeros(Nlayer) @@ -421,15 +364,14 @@ def getCoatLayers(ifo, dOpt): return nLayer, aLayer, bLayer, dLayer, sLayer -def getCoatAvg(ifo, dOpt): +def getCoatAvg(materials, wavelength, dOpt): """Coating average properties - (see getCoatTOPos for example usage) - - ifo = parameter struct from IFOmodel.m - dOpt = optical thickness / lambda of each layer - = geometrical thickness * refractive index / lambda + :materials: gwinc optic materials structure + :wavelength: laser wavelength + :dOpt: coating layer thickness array (Nlayer x 1) + :returns: tuple of: dc = total thickness (meters) Cc = heat capacity Kc = thermal diffusivity @@ -437,33 +379,33 @@ def getCoatAvg(ifo, dOpt): """ # coating parameters - pS = ifo.Materials.Substrate - pC = ifo.Materials.Coating - + pS = materials.Substrate + pC = materials.Coating + alphaS = pS.MassAlpha C_S = pS.MassCM * pS.MassDensity sigS = pS.MirrorSigma - + C_L = pC.CVlown K_L = pC.ThermalDiffusivitylown C_H = pC.CVhighn K_H = pC.ThermalDiffusivityhighn - + # compute refractive index, effective alpha and beta - junk1, junk2, junk3, dLayer, junk4 = getCoatLayers(ifo, dOpt) - + junk1, junk2, junk3, dLayer, junk4 = getCoatLayers(materials, wavelength, dOpt) + # heat capacity dc = sum(dLayer) dL = sum(dLayer[::2]) dH = sum(dLayer[1::2]) Cc = (C_L * dL + C_H * dH) / dc - + # thermal diffusivity KinvL = 1 / K_L KinvH = 1 / K_H Kc = dc / (KinvL * dL + KinvH * dH) - + # effective substrate thermal expansion aSub = 2 * alphaS * (1 + sigS) * Cc / C_S @@ -473,17 +415,18 @@ def getCoatAvg(ifo, dOpt): def getCoatTOPhase(nIn, nOut, nLayer, dOpt, aLayer, bLayer, sLayer): """Coating reflection phase derivatives w.r.t. temperature - nIn = refractive index of input medium (e.g., vacuum = 1) - nOut = refractive index of output medium (e.g., SiO2 = 1.45231 @ 1064nm) - nLayer = refractive index of each layer, ordered input to output (N x 1) - dOpt = optical thickness / lambda of each layer + :nIn: refractive index of input medium (e.g., vacuum = 1) + :nOut: refractive index of output medium (e.g., SiO2 = 1.45231 @ 1064nm) + :nLayer: refractive index of each layer, ordered input to output (N x 1) + :dOpt: optical thickness / lambda of each layer = geometrical thickness * refractive index / lambda - aLayer = change in geometrical thickness with temperature - = the effective thermal expansion coeffient of the coating layer - bLayer = change in refractive index with temperature - = dn/dT - = dd/dT - n * a + :aLayer: change in geometrical thickness with temperature + = the effective thermal expansion coeffient of the coating layer + :bLayer: change in refractive index with temperature + = dn/dT + = dd/dT - n * a + :returns: tuple of: dphi_dT = total thermo-optic phase derivative with respect to temperature = dphi_TE + dphi_TR dphi_TE = thermo-elastic phase derivative (dphi / dT) @@ -494,8 +437,9 @@ def getCoatTOPhase(nIn, nOut, nLayer, dOpt, aLayer, bLayer, sLayer): a_Ta2O5 ~ 3.5 * alpha_Ta2O5 a_SiO2 ~ 2.3 * alpha_SiO2 - see getCoatTOPos for more information - (see also T080101) + See :getCoatTOPos: for more information. + + See LIGO-T080101. """ # coating reflectivity calc @@ -519,53 +463,48 @@ def getCoatTOPhase(nIn, nOut, nLayer, dOpt, aLayer, bLayer, sLayer): return dphi_dT, dphi_TE, dphi_TR, rCoat -def getCoatFiniteCorr(ifo, wBeam, dOpt): +def getCoatFiniteCorr(materials, wavelength, wBeam, dOpt): """Finite mirror size correction + :materials: gwinc optic materials structure + :wavelength: laser wavelength + :wBeam: beam radius (at 1 / e^2 power) + :dOpt: coating layer thickness array (Nlayer x 1) + Uses correction factor from PLA 2003 vol 312 pg 244-255 "Thermodynamical fluctuations in optical mirror coatings" by V. B. Braginsky and S. P. Vyatchanin http://arxiv.org/abs/cond-mat/0302617 - ifo = parameter struct from IFOmodel.m - opticName = name of the Optic struct to use for wBeam and dOpt - wBeam = ifoArg.Optics.(opticName).BeamRadius - dOpt = ifoArg.Optics.(opticName).CoatLayerOpticalThickness - - wBeam = beam radius (at 1 / e^2 power) - dOpt = optical thickness / lambda of each layer - = geometrical thickness * refractive index / lambda - (see getCoatTOPos for example usage) version 1 by Sam Wald, 2008 """ # parameter extraction - R = ifo.Materials.MassRadius #substrate radius - H = ifo.Materials.MassThickness #substrate thickness - lambda_ = ifo.Laser.Wavelength - - alphaS = ifo.Materials.Substrate.MassAlpha - C_S = ifo.Materials.Substrate.MassCM * ifo.Materials.Substrate.MassDensity - Y_S = ifo.Materials.Substrate.MirrorY - sigS = ifo.Materials.Substrate.MirrorSigma - - alphaL = ifo.Materials.Coating.Alphalown - C_L = ifo.Materials.Coating.CVlown - Y_L = ifo.Materials.Coating.Ylown - sigL = ifo.Materials.Coating.Sigmalown - nL = ifo.Materials.Coating.Indexlown - - alphaH = ifo.Materials.Coating.Alphahighn - C_H = ifo.Materials.Coating.CVhighn - Y_H = ifo.Materials.Coating.Yhighn - sigH = ifo.Materials.Coating.Sigmahighn - nH = ifo.Materials.Coating.Indexhighn + R = materials.MassRadius #substrate radius + H = materials.MassThickness #substrate thickness + + alphaS = materials.Substrate.MassAlpha + C_S = materials.Substrate.MassCM * materials.Substrate.MassDensity + Y_S = materials.Substrate.MirrorY + sigS = materials.Substrate.MirrorSigma + + alphaL = materials.Coating.Alphalown + C_L = materials.Coating.CVlown + Y_L = materials.Coating.Ylown + sigL = materials.Coating.Sigmalown + nL = materials.Coating.Indexlown + + alphaH = materials.Coating.Alphahighn + C_H = materials.Coating.CVhighn + Y_H = materials.Coating.Yhighn + sigH = materials.Coating.Sigmahighn + nH = materials.Coating.Indexhighn # coating sums - dL = lambda_ * sum(dOpt[::2]) / nL - dH = lambda_ * sum(dOpt[1::2]) / nH + dL = wavelength * sum(dOpt[::2]) / nL + dH = wavelength * sum(dOpt[1::2]) / nH dc = dH + dL # AVERAGE SPECIFIC HEAT (simple volume average for coating) @@ -597,7 +536,7 @@ def getCoatFiniteCorr(ifo, wBeam, dOpt): # between eq 77 and 78 km = zeta / R Qm = exp(-2 * km * H) - pm = exp(-km**2 * r0**2 / 4) / j0m; # left out factor of pi * R^2 in denominator + pm = exp(-km**2 * r0**2 / 4) / j0m # left out factor of pi * R^2 in denominator # eq 88 Lm = Xr - Zf * (1 + sigS) + (Yr * (1 - 2 * sigS) + Zf - 2 * Cr) * \ @@ -613,26 +552,23 @@ def getCoatFiniteCorr(ifo, wBeam, dOpt): # eq 92 Cfsm = sqrt((r0**2 * P) / (2 * R**2 * (1 + sigS)**2 * LAMBDA**2)) + return Cfsm -def getCoatDopt(ifo, T, dL, dCap=0.5): +def getCoatDopt(materials, T, dL, dCap=0.5): """Coating layer optical thicknesses to match desired transmission - ifo = gwinc IFO model, or vector of 3 refractive indexes [nS, nL, nH] - nS, nL, nH = refractive index of substrate, low and high-n materials - nL is used for the even layers, nH for odd layers - this algorithm may fail if nS > nL - opticName = name of the Optic struct to use for T, dL and dCap - T = power transmission of coating - dL = optical thickness of low-n layers - high-n layers have dH = 0.5 - dL - dCap = first layer (low-n) thickness (default 0.5) - dOpt = optical thickness vector Nlayer x 1 - + :materials: gwinc optic materials structure + :T: power transmission of coating + :dL: optical thickness of low-n layers (high-n layers have dH = 0.5 - dL) + :dCap: first layer (low-n) thickness (default 0.5) + + :returns: optical thickness array Nlayer x 1 (dOpt) + """ ############################################## - def getTrans(ifo, Ndblt, dL, dH, dCap, dTweak): + def getTrans(materials, Ndblt, dL, dH, dCap, dTweak): # the optical thickness vector dOpt = zeros(2 * Ndblt) @@ -644,16 +580,16 @@ def getCoatDopt(ifo, T, dL, dCap=0.5): T = zeros(N) for n in range(N): dOpt[-1] = dTweak[n] - r = getCoatRefl(ifo, dOpt)[0] + r = getCoatRefl(materials, dOpt)[0] T[n] = 1 - abs(r**2) return T ############################################## - def getTweak(ifo, T, Ndblt, dL, dH, dCap, dScan, Nfit): + def getTweak(materials, T, Ndblt, dL, dH, dCap, dScan, Nfit): # tweak bottom layer - Tn = getTrans(ifo, Ndblt, dL, dH, dCap, dScan) + Tn = getTrans(materials, Ndblt, dL, dH, dCap, dScan) pf = polyfit(dScan, Tn - T, Nfit) rts = roots(pf) if not any((imag(rts) == 0) & (rts > 0)): @@ -663,7 +599,7 @@ def getCoatDopt(ifo, T, dL, dCap=0.5): dTweak = real(min(rts[(imag(rts) == 0) & (rts > 0)])) # compute T for this dTweak - Td = getTrans(ifo, Ndblt, dL, dH, dCap, np.array([dTweak])) + Td = getTrans(materials, Ndblt, dL, dH, dCap, np.array([dTweak])) return dTweak, Td @@ -675,13 +611,13 @@ def getCoatDopt(ifo, T, dL, dCap=0.5): # pause(1) # get IFO model stuff (or create it for other functions) - pS = ifo.Materials.Substrate - pC = ifo.Materials.Coating + pS = materials.Substrate + pC = materials.Coating nS = pS.RefractiveIndex nL = pC.Indexlown nH = pC.Indexhighn - + ######################## # find number of quarter-wave layers required, as first guess nR = nH / nL @@ -691,37 +627,37 @@ def getCoatDopt(ifo, T, dL, dCap=0.5): # search through number of doublets to find Ndblt # which gives T lower than required dH = 0.5 - dL - Tn = getTrans(ifo, Ndblt, dL, dH, dCap, np.array([dH])) + Tn = getTrans(materials, Ndblt, dL, dH, dCap, np.array([dH])) while Tn < T and Ndblt > 1: # strange, but T is too low... remove doublets Ndblt = Ndblt - 1 - Tn = getTrans(ifo, Ndblt, dL, dH, dCap, np.array([dH])) + Tn = getTrans(materials, Ndblt, dL, dH, dCap, np.array([dH])) while Tn > T and Ndblt < 1e3: # add doublets until T > tN Ndblt = Ndblt + 1 - Tn = getTrans(ifo, Ndblt, dL, dH, dCap, np.array([dH])) + Tn = getTrans(materials, Ndblt, dL, dH, dCap, np.array([dH])) ######################## # tweak bottom layer delta = 0.01 dScan = np.arange(0, 0.25+delta, delta) - dTweak = getTweak(ifo, T, Ndblt, dL, dH, dCap, dScan, 5)[0] + dTweak = getTweak(materials, T, Ndblt, dL, dH, dCap, dScan, 5)[0] if not dTweak: if nS > nL: raise Exception('Coating tweak layer not sufficient since nS > nL.') else: raise Exception('Coating tweak layer not found... very strange.') - + # now that we are close, get a better result with a linear fit delta = 0.001 dScan = np.linspace(dTweak - 3*delta, dTweak + 3*delta, 7) - dTweak, Td = getTweak(ifo, T, Ndblt, dL, dH, dCap, dScan, 3) + dTweak, Td = getTweak(materials, T, Ndblt, dL, dH, dCap, dScan, 3) # negative values are bad if dTweak < 0.01: dTweak = 0.01 - + # check the result if abs(log(Td / T)) > 1e-3: print('Exact coating tweak layer not found... %g%% error.' % abs(log(Td / T))) @@ -737,23 +673,17 @@ def getCoatDopt(ifo, T, dL, dCap=0.5): return dOpt -def getCoatRefl(ifo, dOpt): +def getCoatRefl(materials, dOpt): """Amplitude reflectivity, with phase, of a coating - ifo = parameter struct from IFOmodel.m - dOpt = optical thickness / lambda of each layer - = geometrical thickness * refractive index / lambda - - rCoat = amplitude reflectivity of coating (complex) = rbar(0) - dcdp = d reflection phase / d round-trip layer phase - rbar = amplitude reflectivity of coating from this layer down - r = amplitude reflectivity of this interface (r(1) is nIn to nLayer(1)) + :materials: gwinc optic materials sturcutre + :dOpt: coating layer thickness array (Nlayer x 1) - cf ewa/multidiel1.m + :returns: see return value of :geteCoatRefl2: """ - pS = ifo.Materials.Substrate - pC = ifo.Materials.Coating + pS = materials.Substrate + pC = materials.Coating nS = pS.RefractiveIndex nL = pC.Indexlown @@ -775,22 +705,21 @@ def getCoatRefl(ifo, dOpt): def getCoatRefl2(nIn, nOut, nLayer, dOpt): """Coating reflection and phase derivatives - nIn = refractive index of input medium (e.g., vacuum = 1) - nOut = refractive index of output medium (e.g., SiO2 = 1.45231 @ 1064nm) - nLayer = refractive index of each layer, ordered input to output (N x 1) - dOpt = optical thickness / lambda of each layer - = geometrical thickness * refractive index / lambda + :nIn: refractive index of input medium (e.g., vacuum = 1) + :nOut: refractive index of output medium (e.g., SiO2 = 1.45231 @ 1064nm) + :nLayer: refractive index of each layer, ordered input to output (N x 1) + :dOpt: optical thickness / lambda of each layer, + geometrical thickness * refractive index / lambda + :returns: tuple of: rCoat = amplitude reflectivity of coating (complex) = rbar(0) dcdp = d reflection phase / d round-trip layer phase rbar = amplitude reflectivity of coating from this layer down r = amplitude reflectivity of this interface (r(1) is nIn to nLayer(1)) - see GWINC getCoatRefl and getCoatTOPhase for more information - (see also T080101) + See LIGO-T080101. """ - # Z-dir (1 => away from the substrate, -1 => into the substrate) zdir = 1 diff --git a/gwinc/precomp.py b/gwinc/precomp.py index d9a616ef..882c9602 100644 --- a/gwinc/precomp.py +++ b/gwinc/precomp.py @@ -56,11 +56,11 @@ def precompIFO(f, ifoin, PRfixed=True): T = ifo.Optics.ITM.Transmittance dL = ifo.Optics.ITM.CoatingThicknessLown dCap = ifo.Optics.ITM.CoatingThicknessCap - ifo.Optics.ITM.CoatLayerOpticalThickness = getCoatDopt(ifo, T, dL, dCap=dCap) + ifo.Optics.ITM.CoatLayerOpticalThickness = getCoatDopt(ifo.Materials, T, dL, dCap=dCap) T = ifo.Optics.ETM.Transmittance dL = ifo.Optics.ETM.CoatingThicknessLown dCap = ifo.Optics.ETM.CoatingThicknessCap - ifo.Optics.ETM.CoatLayerOpticalThickness = getCoatDopt(ifo, T, dL, dCap=dCap) + ifo.Optics.ETM.CoatLayerOpticalThickness = getCoatDopt(ifo.Materials, T, dL, dCap=dCap) ############################## # beam parameters -- GitLab