diff --git a/gwinc/gwinc.py b/gwinc/gwinc.py index 80335661ccc16e5531a5f71a9c28021b2c01f4e5..268a30e26096233e891d115bc951cced25b2db5c 100644 --- a/gwinc/gwinc.py +++ b/gwinc/gwinc.py @@ -1,8 +1,8 @@ from __future__ import division -import copy import numpy as np from numpy import pi, sqrt, sin, exp, abs, log10 import scipy.constants +from numpy import pi, sqrt from collections import OrderedDict import logging @@ -12,33 +12,6 @@ from . import noise from .plot import plot_noise -def dhdl(f, armlen): - """Strain to length conversion for noise power spetra - - This takes into account the GW wavelength and is only important - when this is comparable to the detector arm length. - - From R. Schilling, CQG 14 (1997) 1513-1519, equation 5, - with n = 1, nu = 0.05, ignoring overall phase and cos(nu)^2. - A small value of nu is used instead of zero to avoid infinities. - - Returns the square of the dh/dL function, and the same divided by - the arm length squared. - - """ - c = scipy.constants.c - nu_small = 0.05 - omega_arm = pi * f * armlen / c - omega_arm_f = (1 - sin(nu_small)) * pi * f * armlen / c - omega_arm_b = (1 + sin(nu_small)) * pi * f * armlen / c - sinc_sqr = 4 / abs(sin(omega_arm_f) * exp(-1j * omega_arm) / omega_arm_f - + sin(omega_arm_b) * exp(1j * omega_arm) / omega_arm_b)**2 - # keep DC value equal to 1 - sinc_sqr /= sinc_sqr[0] - dhdl_sqr = sinc_sqr / armlen**2 - return dhdl_sqr, sinc_sqr - - def noise_calc(ifo, f): """Calculate all IFO noises and return as dict @@ -49,32 +22,6 @@ def noise_calc(ifo, f): # suspension transfer function # # used in seismic and susptherm calculations - - fname = eval('suspension.susp{}'.format(ifo.Suspension.Type)) - hForce, vForce, hTable, vTable = fname(f, ifo) - - # if the suspension code supports different temps for the stages - try: - # full TF (conventional) - ifo.Suspension.hForce = hForce.fullylossy - ifo.Suspension.vForce = vForce.fullylossy - # TFs with each stage lossy - ifo.Suspension.hForce_singlylossy = hForce.singlylossy - ifo.Suspension.vForce_singlylossy = vForce.singlylossy - except: - ifo.Suspension.hForce = hForce - ifo.Suspension.vForce = vForce - - ifo.Suspension.hTable = hTable - ifo.Suspension.vTable = vTable - - ############################## - # strain to length conversion - # - # used for converting displacement to strain in all noise calculations - - ifo.gwinc.dhdl_sqr, ifo.gwinc.sinc_sqr = dhdl(f, ifo.Infrastructure.Length) - ############################## noises = OrderedDict() @@ -149,10 +96,9 @@ def gwinc(freq, ifoin, source=None, plot=False, PRfixed=True): Returns tuple of (score, noises, ifo) """ - ifo = copy.deepcopy(ifoin) - # add some precomputed info to the ifo struct - ifo = precompIFO(ifo, PRfixed) + #this implicitly deepcopies and the return value is the copy + ifo = precompIFO(freq, ifoin, PRfixed) pbs = ifo.gwinc.pbs parm = ifo.gwinc.parm @@ -164,6 +110,8 @@ def gwinc(freq, ifoin, source=None, plot=False, PRfixed=True): noises = noise_calc(ifo, freq) + #TODO decide if all this below this should remain, since it is already inside of __main__ + # report astrophysical scores if so desired score = None if source: @@ -229,5 +177,4 @@ def gwinc(freq, ifoin, source=None, plot=False, PRfixed=True): logging.info('Stochastic Omega: %4.1g Universes' % score.Omega) plot_noise(ifo, noises) - return score, noises, ifo diff --git a/gwinc/precomp.py b/gwinc/precomp.py index 7e044e1f5fbcecd51a4c14826c81fb68d35caabb..e357fc2a46792e6a2f497508e8200fb669cd69e1 100644 --- a/gwinc/precomp.py +++ b/gwinc/precomp.py @@ -1,22 +1,27 @@ from __future__ import division -from numpy import pi, sqrt +from numpy import pi, sqrt, sin, exp from scipy.io import loadmat import scipy.special import logging +import copy +from . import suspension from .const import CONSTANTS from .struct import Struct from .noise.coatingthermal import getCoatDopt +from . import util -def precompIFO(ifo, PRfixed=True): +def precompIFO(F_Hz, ifoin, PRfixed=True): """Add precomputed data to the IFO model. To prevent recomputation of these precomputed data, if the ifo argument contains ifo.gwinc.PRfixed, and this matches the argument PRfixed, no changes are made. + This function DOES NOT modify IFO. Its return value is a copy of IFO with precomputations filled out. """ + ifo = copy.deepcopy(ifoin) if 'gwinc' not in ifo: ifo.gwinc = Struct() @@ -71,7 +76,7 @@ def precompIFO(ifo, PRfixed=True): if (g1 * g2 * (1 - g1 * g2)) <= 0: raise Exception('Unstable arm cavity g-factors. Change ifo.Optics.Curvature') elif gcav < 1e-3: - log.warning('Nearly unstable arm cavity g-factors. Reconsider ifo.Optics.Curvature') + logging.warning('Nearly unstable arm cavity g-factors. Reconsider ifo.Optics.Curvature') ws = sqrt(armlen * ifo.Laser.Wavelength / pi) w1 = ws * sqrt(abs(g2) / gcav) @@ -129,6 +134,36 @@ def precompIFO(ifo, PRfixed=True): ifo.Seismic.darmseis_f = darmsei['darmseis_f'][0] ifo.Seismic.darmseis_x = darmsei['darmseis_x'][0] + # -------------------------------------------------------- + # Suspension + # if the suspension code supports different temps for the stages + fname = eval('suspension.susp{}'.format(ifo.Suspension.Type)) + hForce, vForce, hTable, vTable = fname(F_Hz, ifo) + + try: + # full TF (conventional) + ifo.Suspension.hForce = hForce.fullylossy + ifo.Suspension.vForce = vForce.fullylossy + # TFs with each stage lossy + ifo.Suspension.hForce_singlylossy = hForce.singlylossy + ifo.Suspension.vForce_singlylossy = vForce.singlylossy + except: + ifo.Suspension.hForce = hForce + ifo.Suspension.vForce = vForce + + ifo.Suspension.hTable = hTable + ifo.Suspension.vTable = vTable + + ############################## + # strain to length conversion + # + # used for converting displacement to strain in all noise calculations + + ifo.gwinc.dhdl_sqr, ifo.gwinc.sinc_sqr = dhdl(F_Hz, ifo.Infrastructure.Length) + + ############################## + # If we are precomputing everything else, might as well simply function call API by sticking in the F_Hz + ifo.gwinc.F_Hz = F_Hz return ifo @@ -220,3 +255,29 @@ def precompQuantum(ifo): fGammaIFO = fGammaArm * ((1 + rSR) / (1 - rSR)) return fSQL, fGammaIFO, fGammaArm + +def dhdl(f, armlen): + """Strain to length conversion for noise power spetra + + This takes into account the GW wavelength and is only important + when this is comparable to the detector arm length. + + From R. Schilling, CQG 14 (1997) 1513-1519, equation 5, + with n = 1, nu = 0.05, ignoring overall phase and cos(nu)^2. + A small value of nu is used instead of zero to avoid infinities. + + Returns the square of the dh/dL function, and the same divided by + the arm length squared. + + """ + c = scipy.constants.c + nu_small = 0.05 + omega_arm = pi * f * armlen / c + omega_arm_f = (1 - sin(nu_small)) * pi * f * armlen / c + omega_arm_b = (1 + sin(nu_small)) * pi * f * armlen / c + sinc_sqr = 4 / abs(sin(omega_arm_f) * exp(-1j * omega_arm) / omega_arm_f + + sin(omega_arm_b) * exp(1j * omega_arm) / omega_arm_b)**2 + # keep DC value equal to 1 + sinc_sqr /= sinc_sqr[0] + dhdl_sqr = sinc_sqr / armlen**2 + return dhdl_sqr, sinc_sqr