Maintenance will be performed on git.ligo.org, chat.ligo.org, containers.ligo.org, and docs.ligo.org, starting at approximately 9am MST on Tuesday 7th December 2021. It is expected to take around 15 minutes and there will be a short period of downtime towards the end of the maintenance window. Please address any comments, concerns, or questions to computing-help@igwn.org.

Commit 7bda7f05 authored by Kevin Kuns's avatar Kevin Kuns
Browse files

Merge branch 'inheritance' into 'master'

simple inheritance in yaml files through load_budget

See merge request !127
parents ede743c8 369acea5
Pipeline #297842 passed with stages
in 22 minutes and 41 seconds
[flake8]
ignore = E226,E741,E266,W503
max-line-length = 140
# E226, missing whitespace around arithmetic operator: quantum.py currently needs large changes to avoid this
# E741, "l" is a bad variable name: Gwinc uses "l" in a few reasonable places
# E266, Too many leading '#' for block comment: There are some reasonable instances of comments that trigger this
# W503, binary operator at start of line: This allows using parentheses to break equations
......@@ -25,7 +25,7 @@ sys.path.insert(0, os.path.abspath('..'))
#gwinc must be importable to build the docs properly anyway, using apidoc, so
#import it now for the __version__ parameter
import gwinc
import gwinc # noqa
# -- General configuration ------------------------------------------------
......
......@@ -92,7 +92,7 @@ def load_budget(name_or_path, freq=None, bname=None):
If `bname` is specified the Budget class with that name will be
loaded from the budget module. Otherwise, the Budget class with
the same name as the budget module will be load.
the same name as the budget module will be loaded.
If the budget is a package directory which includes an 'ifo.yaml'
file the ifo Struct will be loaded from that file and assigned to
......@@ -119,10 +119,24 @@ def load_budget(name_or_path, freq=None, bname=None):
if ext in Struct.STRUCT_EXT:
logger.info("loading struct {}...".format(path))
ifo = Struct.from_file(path)
bname = 'aLIGO'
modname = 'gwinc.ifo.aLIGO'
ifo = Struct.from_file(path, _pass_inherit=True)
inherit_ifo = ifo.get('+inherit', None)
if inherit_ifo is not None:
del ifo['+inherit']
# make the inherited path relative to the loaded path
# if it is a yml file
if os.path.splitext(inherit_ifo)[1] in Struct.STRUCT_EXT:
base = os.path.split(path)[0]
inherit_ifo = os.path.join(base, inherit_ifo)
inherit_budget = load_budget(inherit_ifo, freq=freq, bname=bname)
pre_ifo = inherit_budget.ifo
pre_ifo.update(ifo, overwrite_atoms=False)
inherit_budget.update(ifo=pre_ifo)
return inherit_budget
else:
modname = 'gwinc.ifo.aLIGO'
else:
bname = bname or base
modname = path
......@@ -208,13 +222,15 @@ def gwinc(freq, ifo, source=None, plot=False, PRfixed=True):
logger.info('Power on BS: %7.2f W' % pbs)
# coating and substrate thermal load on the ITM
PowAbsITM = (pbs/2) * \
np.hstack([(finesse*2/np.pi) * ifo.Optics.ITM.CoatingAbsorption,
(2 * ifo.Materials.MassThickness) * ifo.Optics.ITM.SubstrateAbsorption])
PowAbsITM = (
(pbs/2)
* np.hstack([
(finesse*2/np.pi) * ifo.Optics.ITM.CoatingAbsorption,
(2 * ifo.Materials.MassThickness) * ifo.Optics.ITM.SubstrateAbsorption])
)
logger.info('Thermal load on ITM: %8.3f W' % sum(PowAbsITM))
logger.info('Thermal load on BS: %8.3f W' %
(ifo.Materials.MassThickness*ifo.Optics.SubstrateAbsorption*pbs))
logger.info('Thermal load on BS: %8.3f W' % (ifo.Materials.MassThickness*ifo.Optics.SubstrateAbsorption*pbs))
if (ifo.Laser.Power*prfactor != pbs):
logger.info('Lensing limited input power: %7.2f W' % (pbs/prfactor))
......
......@@ -5,6 +5,7 @@ from __future__ import division
import numpy as np
from numpy import pi, sqrt, arctan, sin, cos, exp, log10, conj
from copy import deepcopy
from collections.abc import Sequence
from .. import logger
from .. import const
......@@ -137,6 +138,7 @@ def shotrad(f, ifo, sustf, power):
sqz_params.alpha = sqzOptimalSqueezeAngle(Mifo, sqz_params.eta)
vHD = np.array([[sin(sqz_params.eta), cos(sqz_params.eta)]])
def homodyne(signal):
"""Readout the eta quadrature of the signal signal
"""
......@@ -242,7 +244,6 @@ def shotradSignalRecycled(f, ifo, sustf, power):
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.Suspension.Stage[0].Mass # Mirror mass [kg]
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bsloss = ifo.Optics.BSLoss # BS Loss [Power]
......@@ -250,7 +251,7 @@ def shotradSignalRecycled(f, ifo, sustf, power):
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]
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]
......@@ -354,8 +355,7 @@ def shotradSignalRecycled(f, ifo, sustf, power):
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]]))
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
......@@ -579,9 +579,13 @@ def propagate_noise_fc_ifo(f, ifo, Mifo, Mnoise, sqz_params, alpha):
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Inject squeezed field into the IFO via some filter cavities
if sqz_params.sqzType == 'Freq Dependent' and 'FilterCavity' in ifo.Squeezer:
logger.debug(' Applying %d input filter cavities' % np.atleast_1d(ifo.Squeezer.FilterCavity).size)
if not isinstance(ifo.Squeezer.FilterCavity, Sequence):
fc_list = [ifo.Squeezer.FilterCavity]
else:
fc_list = ifo.Squeezer.FilterCavity
logger.debug(' Applying %d input filter cavities' % len(fc_list))
Mr, Msqz = sqzFilterCavityChain(
f, np.atleast_1d(ifo.Squeezer.FilterCavity), Msqz)
f, fc_list, Msqz)
# apply the IFO dependent squeezing matrix to get the total noise
# due to quantum fluctuations coming in from the AS port
......@@ -658,8 +662,6 @@ def getProdTF(lhs, rhs):
# check matrix size
if lhs.shape[1] != rhs.shape[0]:
raise Exception('Matrix size mismatch size(lhs, 2) = %d != %d = size(rhs, 1)' % (lhs.shape[1], rhs.shape[0]))
N = lhs.shape[0]
M = rhs.shape[1]
if len(lhs.shape) == 3:
lhs = np.transpose(lhs, axes=(2, 0, 1))
if len(rhs.shape) == 3:
......@@ -739,14 +741,14 @@ def sqzFilterCavityChain(f, params, Mn, key='FC'):
Mc = make2x2TF(np.ones(f.shape), 0, 0, 1)
# loop through the filter cavites
for k in range(params.size):
for k, fc in enumerate(params):
# extract parameters for this filter cavity
Lf = params[k].L
fdetune = params[k].fdetune
Ti = params[k].Ti
Te = params[k].Te
Lrt = params[k].Lrt
theta = params[k].Rot
Lf = fc.L
fdetune = fc.fdetune
Ti = fc.Ti
Te = fc.Te
Lrt = fc.Lrt
theta = fc.Rot
# compute new Mn
fc_key = key + str(k)
......@@ -807,22 +809,21 @@ def sqzFilterCavity(f, Lcav, Ti, Te, Lrt, fdetune, MinR, MinT=1, key='FC'):
c = const.c
omega = 2 * pi * f
wf = 2 * pi * fdetune
Phi_p = 2 * (omega-wf)* Lcav / c
Phi_m = 2 * (-omega-wf)* Lcav / c
Phi_p = 2 * (omega-wf) * Lcav / c
Phi_m = 2 * (-omega-wf) * Lcav / c
ephi_p = exp(1j * Phi_p)
ephi_m = exp(1j * Phi_m)
# cavity gains
g_p = 1 / ( 1 - rr * ephi_p)
g_m = 1 / ( 1 - rr * ephi_m)
g_p = 1 / (1 - rr * ephi_p)
g_m = 1 / (1 - rr * ephi_m)
# Reflectivity for vacuum flactuation entering the cavity from
# the input mirror (check sign)
r_p = ri - re * Ti * ephi_p * g_p
r_m = ri - re * Ti * ephi_m * g_m
# Transmissivity for vacuum flactuation entering the cavity from
# the back mirror (check sign)
t_p = sqrt(Ti * Te * ephi_p) * g_p
......
This diff is collapsed.
......@@ -4,5 +4,11 @@ python_files = test_*.py T*_*.py
python_functions = test_* T*
usefixtures = closefigs
markers =
slow: marks tests as slow (deselect with '-m "not slow"')
fast: marks tests as being fast, usually it does not make plots
logic: is a test of the code logic
noise: is a test of the noise curves
[pytest-watch]
ignore = .*
+inherit: 'Aplus'
# test that list merging works
Suspension:
Stage:
# Stage1
-
# Stage2
-
# Stage3
-
# Stage4
- Mass: 30
Squeezer:
AmplitudedB: 14 # SQZ amplitude [dB]
InjectionLoss: 0.02 # power loss to sqz
+inherit: 'Aplus_mod.yaml'
# test that list merging works
Suspension:
Stage:
# Stage1
-
# Stage2
-
# Stage3
- Mass: 30
Squeezer:
AmplitudedB: 12 # SQZ amplitude [dB]
# this isn't allowed, yet
materials:
+inherit: 'Aplus'
"""
"""
import pytest
from gwinc import load_budget
@pytest.mark.fast
@pytest.mark.logic
def test_inherit_load(pprint, tpath_join, fpath_join):
fpath = fpath_join('Aplus_mod.yaml')
B_inherit = load_budget(fpath)
B_orig = load_budget('Aplus')
pprint(B_inherit.ifo)
pprint("ACTUAL TEST")
pprint(B_inherit.ifo.diff(B_orig.ifo))
assert(
sorted(B_inherit.ifo.diff(B_orig.ifo))
== sorted([
('Suspension.Stage[3].Mass', 30, 22.1),
('Squeezer.AmplitudedB', 14, 12),
('Squeezer.InjectionLoss', 0.02, 0.05)])
)
fpath2 = fpath_join('Aplus_mod2.yaml')
B_inherit2 = load_budget(fpath2)
pprint(B_inherit2.ifo.diff(B_orig.ifo))
assert(
sorted(B_inherit2.ifo.diff(B_orig.ifo))
== sorted([
('Suspension.Stage[2].Mass', 30, 21.8),
('Suspension.Stage[3].Mass', 30, 22.1),
('Squeezer.InjectionLoss', 0.02, 0.05)
])
)
@pytest.mark.fast
@pytest.mark.logic
def test_inherit_fail(pprint, tpath_join, fpath_join):
"""
This test shows that the interim logic that Struct.from_file checks for and fails when it gets "+inherit" keys.
Those will be allowable at a later time.
"""
fpath2 = fpath_join('inherit_fail.yaml')
with pytest.raises(RuntimeError):
B_inherit2 = load_budget(fpath2)
lists:
test_nonelist:
-
-
dicts:
test_nonedict:
A:
B:
"""
"""
import numpy as np
from os import path
from gwinc import Struct
import pylab as pyl
def test_load(pprint, tpath_join, fpath_join):
fpath = fpath_join('test_load.yml')
yml = Struct.from_file(fpath)
pprint("full yaml")
pprint(yml)
pprint("individual tests")
pprint(yml.lists.test_nonelist)
assert(yml.lists.test_nonelist == [None, None])
pprint(yml.dicts.test_nonedict)
S_cmp = Struct({'A': None, 'B': None})
pprint(yml.dicts.test_nonedict.diff(S_cmp))
assert(yml.dicts.test_nonedict == S_cmp)
def test_struct_load_Sequences():
# test of the ordering of value types
# https://git.ligo.org/gwinc/pygwinc/-/merge_requests/127#note_458256
s = Struct({'a': 'b'})
s.update({'a': 'c'})
return
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment