Commit 4824a81c authored by Andreas Freise's avatar Andreas Freise
Browse files

some refactoring, starting to add DOFs

parent 28181fe4
Pipeline #1727 passed with stage
in 20 seconds
......@@ -8,21 +8,150 @@ import math
import copy
import warnings
import cmath
from pykat import finesse
import pykat.components
import pykat.exceptions as pkex
import pykat.external.peakdetect as peak
import matplotlib.pyplot as plt
import pkg_resources
nsilica=1.44963098985906
class aLIGO(object):
def __init__(self, _name="default"):
"""
Object storing the Finesse input file and some auxilliary information
about Avanced LIGO interferometers.
"""
def __init__(self, _name="default", katfile=None, debug=False):
names = ['default', 'LLO', 'LHO']
if _name not in names:
printf("aLIGO name `{}' not recognised, must be 'default', 'LLO' or 'LHO'",_name)
if debug:
self.kat = finesse.kat(tempdir=".",tempname="test")
else:
self.kat = finesse.kat()
if katfile:
self.kat.loadKatFile(katfile)
else:
if _name not in names: # TODO different files not yet implemented
printf("aLIGO name `{}' not recognised, must be 'default', 'LLO' or 'LHO'",_name)
_data_path=pkg_resources.resource_filename('pykat.gw_detectors','finesse_files/')
#print(data_path)
self.kat.loadKatFile(_data_path+"aLIGO.kat")
self.POP_f1 = port("POP", "nPOP", "f1", phase=101)
self.POP_f2 = port("POP", "nPOP", "f2", phase=13)
self.REFL_f1 = port("REFL", "nREFL", "f1", phase=101)
self.REFL_f2 = port("REFL", "nREFL", "f2", phase=14)
self.AS_DC = port("AS", "nSRM")
# control scheme as in C. Bonf Table C.1 TODO complete citation
self.PRCL = DOF("PRCL", self.POP_f1, "I", "PRM", 1)
self.MICH = DOF("MICH", self.POP_f2, "Q", "BS", 1)
self.CARM = DOF("CARM", self.REFL_f1, "I", ["ETMX", "ETMY"], [1, 1])
self.DARM = DOF("DARM", self.AS_DC, "", ["ETMX", "ETMY"], [1,-1])
self.SRCL = DOF("SRCL", self.REFL_f2, "I", "SRM", 1)
class port(object):
"""
Defining an output port for the interferometer, can be either a
pd or a pd1 detector (for error signal generation).
"""
def __init__(self, _portName, _nodeName, f=None, phase=None):
self.portName = _portName
self.nodeName = _nodeName
self.f=f # demodulation frequency, string "f1", "f2" or "f3"
self.phase = phase # demodulation frequency for I quadrature, float
if f!=None:
self.name = self.portName+"_"+str(self.f)
def errsig(quad="I", sigtype="z"):
if sigtype != "z":
raise pkex.BasePyKatException("alignment signals are not implemented yet")
if self.f==None:
return "pd {} {}".format(name, self.nodeName)
else:
if quad !="I" and quad != "Q":
raise pkex.BasePyKatException("quadrature must be 'I' or 'Q'")
name = self.name+"_"+quad
phase = IQ_phase(quad, self.phase)
return "pd1 {} ${} {} {}".format(name, f1, phase, self.nodeName), name
def IQ_phase(quad, phase):
if quad== "Q":
phase = phase + 90.0
if phase >=360.0 :
phase -= 360.0
return phase
def amplitude(f, n=None, m=None, sigtype="z"):
name = self.name + "_ad"
if n==None and m==None:
return "ad {} {} {}".format(name, f, self.nodeName)
else:
return "ad {} {} {} {} {}".format(name, f, n, m, self.nodeName), name
def transfer(quad="I", fsig=1, phase2=None, sigtype="z"):
if sigtype!="z":
raise pkex.BasePyKatException("alignment signals are not implemented yet")
if self.f==None:
return "pd1 {} {} {} {}".format(name, fsig, phase2, self.nodeName), name
else:
if quad !="I" and quad != "Q":
raise pkex.BasePyKatException("quadrature must be 'I' or 'Q'")
name=self.name+"_"+quad
phase = IQ_phase(quad, self.phase)
if phase2 == None:
return "pd2 {} ${} {} {} {}".format(name, f1, phase, fsig, self.nodeName), name
else:
return "pd2 {} ${} {} {} {} {}".format(name, f1, phase, fsig, phase2, self.nodeName), name
class DOF(object):
"""
Defining a degree of freedom for the interferometer, includes the
objects and how to move them, and the default output port to read
out the DOF signal.
"""
def __init__(self, _DOFName, _port, _quad, _optics, _factors):
self.DOFName = _DOFName
self.port = _port
self.quad = _quad
self.optics=make_list_copy(_optics)
self.factors=make_list_copy(_factors)
def tune(_varName, linlog="lin", xlimits=[-100, 100], steps=200, axis=1):
if linlog not in ["lin", "log"]:
raise pkex.BasePyKatException("linlog must be 'lin' or 'log'")
_tuneStr = "var {} 0\n".format(_varName)
if axis==1:
_tuneStr += "xaxis {} phi {} {} {} {}\n".format(_varName, linlog, xlimits[0], xlimits[1], steps)
elif (axis==2 or axis==3):
_tuneStr += "x{}axis {} phi {} {} {} {}\n".format(axis, _varName, linlog, xlimits[0], xlimits[1], steps)
else:
raise pkex.BasePyKatException("axis must be 1, 2 or 3")
_putStr = ""
for idx, o in enumerate(self.optics):
if self.factors[idx] == 1:
_xStr="$x"
elif self.factors[idx] == -1:
_xStr="$mx"
else:
raise pkex.BasePyKatException("optics factors must be 1 or -1")
_putStr = "\n".join([_putStr, "put* {} phi {}{}".format(o, _xStr, axis)])
_tuneStr += _putStr
return _tuneStr
def fsig(_fsigName):
_fsigStr= ""
for idx, o in enumerate(self.optics):
_fsigStr = "\n".join([_fsigStr, "fsig {} {} {}".format(_fsigName, o, self.factors[idx])])
return _fsigStr
def make_transparent(kat, _components):
"""
Function to make certain mirror or beamsplitter objects transparent
......@@ -135,21 +264,17 @@ def BS_optical_path(thickness, n=nsilica, angle=45.0):
return math.degrees(angle_subst), L
def scan_optics(_kat, _optics, _factors, detector, xlimits=[-100, 100], steps=200, minmax='max', debug=False):
def scan_optics(_kat, _optics, _factors, xlimits=[-100, 100], steps=200):
"""
Scans one or more optics (by changing its tuning) and find the tuning with max/min
output on a sepcific detectos. Useful for pre-tuning cavities or interferometers.
Returns the tuning of the maximum (or minimum) and the precision
Scans one or more optics (by changing its tuning).
Parameters:
optics: list of names of components to be tuned
factors: list of scaling factors for the tuning for each optics, first element must be 1.0
detector: name of detetor to use
xlimits: limits of scan, defaults to [-100, 100]
steps: number of steps to use in scan, default is 200
minmax, string to indicate maximum or minum detection, default 'max'
Usage:
scan_optis(kat, "PRM", 1, "pdout")
scan_optis(kat, ["ETMX", "ETMY", [1, -1], "pdout", minmax='min')
scan_optis(kat, "PRM", 1)
scan_optis(kat, ["ETMX", "ETMY", [1, -1])
"""
kat = _kat.deepcopy()
......@@ -171,18 +296,28 @@ def scan_optics(_kat, _optics, _factors, detector, xlimits=[-100, 100], steps=20
put {2} phi $nx{0}""".format(idx,factors[idx],o))
out = kat.run()
return out
def find_peak(out, detector, minmax='max', debug=False):
"""
Expects an output of a kat scan and find the max/min output on
a sepcific detector. Useful for pre-tuning cavities or interferometers.
Returns the tuning of the maximum (or minimum) and the precision
Parameters:
detector: name of detetor to use
minmax, string to indicate maximum or minum detection, default 'max'
Usage:
find_peak(out, "pdout")
find_peak(out, "pdout", minmax='min')
"""
stepsize = out.x[1]-out.x[0]
print(" stepsize (precision) of scan: {0:g}".format(stepsize))
if debug==True:
plt.figure()
plt.plot(out.x,out[detector])
_max, _min = peak.peakdetect( out[detector],out.x, 1)
if debug==True:
plt.figure()
plt.plot(out.x,out[detector])
print("max: ")
print(_max)
print("min: ")
......
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