diff --git a/pykat/gw_detectors/finesse_files/aLIGO.kat b/pykat/gw_detectors/finesse_files/aLIGO.kat index a2de92b0b63da237e0cb799cb7ead3444cb03281..ef6ce390e994d2489ae3efa9f35c895411239aa5 100644 --- a/pykat/gw_detectors/finesse_files/aLIGO.kat +++ b/pykat/gw_detectors/finesse_files/aLIGO.kat @@ -39,11 +39,13 @@ # should have losses but no reflectivity. Alternatively beamsplitter components # with non-zero reflectivity can be used to detect the AR reflections # - Same as above for PRM and SRM AR coatings +# - change order of `cav' commands, arm cavities need to come first # # Change of parameter values # - BS substrate length were assymetric and did not match substrate thickness, # changed to symmetric 0.0687m, using pykat.GWdetectors.aLIGO.BSpath(0.06) # - changed SRM transmission from 35% to 20%, matching the aLIGO 2015 paper +# - changed arm length to L=3994.4692, see [4], Table 10.2 # # Changes in file structure # - removed length calculation fucntions for PRC and SRC sub-length @@ -54,24 +56,8 @@ # - changed naming for thermal lens components # - changed naming of PRMHR to PRM and node names in PRM substrate # - changed naming of SRMHR to SRM and node names in SRM substrate -# - chnaged name of ITMHR to ITM and ETMHR to ETM -# - -# Laser -# -# Modulation -# -# IMC -# -# PRC -# -# BS -# -# Arms -# - changed arm length to L=3994.4692, see [4], Table 10.2 -# -# SRC -# -# OMC +# - changed name of ITMHR to ITM and ETMHR to ETM +# - changed names of arm spaces from LXarm, LYarm to LX, LY # # @@ -174,7 +160,7 @@ m1 ITMY 0.014 $Mloss $phi_ITMY nITMYs2 nITMY2 attr ITMY Rc -1934 # Y arm length -s LYarm $Larm nITMY2 nETMY1 +s LY $Larm nITMY2 nETMY1 # Y arm end mirror m1 ETMY 5u $Mloss $phi_ETMY nETMY1 nETMYs1 @@ -208,7 +194,7 @@ m1 ITMX 0.014 $Mloss $phi_ITMX nITMXs2 nITMX2 attr ITMX Rc -1934 # X arm length -s LXarm $Larm nITMX2 nETMX1 +s LX $Larm nITMX2 nETMX1 # X arm end mirror m1 ETMX 5u $Mloss $phi_ETMX nETMX1 nETMXs1 @@ -250,12 +236,12 @@ attr SRM Rc -5.6938 ########################################################################### maxtem 4 #cav cavIMC MC2 nMC2in MC2 nMC2refl +cav cavXARM ITMX nITMX2 ETMX nETMX1 +cav cavYARM ITMY nITMY2 ETMY nETMY1 cav cavPRX PRM nPRM2 ITMX nITMXs2 cav cavPRY PRM nPRM2 ITMY nITMYs2 cav cavSRX SRM nSRM1 ITMX nITMXs2 cav cavSRY SRM nSRM1 ITMY nITMYs2 -cav cavXARM ITMX nITMX2 ETMX nETMX1 -cav cavYARM ITMY nITMY2 ETMY nETMY1 # removed OMC ########################################################################### @@ -334,7 +320,6 @@ pd1 AS_f2_Q $f2 103 nSRM2 %%% FTblock locks ########################################################################### - set PRCL_err POP_f1_I re set MICH_err POP_f2_Q re set CARM_err REFL_f1_I re diff --git a/pykat/gw_detectors/ifo.py b/pykat/gw_detectors/ifo.py index 394d9d8b849bbdb29cdc8fe6b46d4ea7d4c41f52..e7964a575287f5c4da7fbce300fa43dbcf80fe43 100644 --- a/pykat/gw_detectors/ifo.py +++ b/pykat/gw_detectors/ifo.py @@ -75,15 +75,15 @@ class aLIGO(object): if "f3" in self.kat.constants.keys(): self.f3 = float(self.kat.constants["f3"].value) # TODO add else here! + # check modultion frequencies + if (5 * self.f1 != self.f2): + print(" ** Warning: modulation frequencies do not match: 5*f1!=f2") # defining a dicotionary for the main mirror positions (tunings) self.tunings = {} self.tunings = self.get_tunings(self.kat) - # compute lengths such as PRC lentgth from individual lengths self.compute_derived_lengths(self.kat) - # check modultion frequencies - if (5 * self.f1 != self.f2): - print(" ** Warning: modulation frequencies do not match: 5*f1!=f2") + # ---------------------------------------------------------------------- # define ports and signals @@ -114,16 +114,16 @@ class aLIGO(object): - def adjust_PRC_length(self, kat): + def adjust_PRC_length(self, kat, verbose=False): """ Adjust PRC length so that it fulfils the requirement lPRC = (N+1/2) * c/(2*f1), see [1] equation C.1 In the current design N=3 """ - print("-- adjusting PRC length") + vprint(verbose, "-- adjusting PRC length") ltmp = 0.5 * clight / self.f1 delta_l = 3.5 * ltmp - self.lPRC - print(" adusting kat.lp1.L by {}m".format(delta_l)) + vprint(verbose, " adusting kat.lp1.L by {:.4g}m".format(delta_l)) kat.lp1.L += delta_l self.compute_derived_lengths(kat) @@ -136,15 +136,19 @@ class aLIGO(object): kat = _kat.deepcopy() fig = plt.figure() ax = fig.add_subplot(1,1,1) - startf = self.f1-400.0 - stopf = self.f1+400.0 + startf = self.f1-4000.0 + stopf = self.f1+4000.0 + if _kat.maxtem == "off": + nmStr = None + else: + nmStr = "0 0" code = """ - ad f1p {0} nPRM2 - ad f1m -{0} nPRM2 - xaxis mod1 f lin {1} {2} 200 + ad f1p {0} {1} nPRM2 + ad f1m {0} -{1} nPRM2 + xaxis mod1 f lin {2} {3} 200 put f1p f $x1 put f1m f $mx1 - """.format(self.f1, startf, stopf) + """.format(nmStr, self.f1, startf, stopf) kat.parseCommands(code) out = kat.run() ax.plot(out.x-self.f1,np.abs(out["f1p"]), label=" f1") @@ -177,13 +181,31 @@ class aLIGO(object): self.lPRC = self.lpr + self.lMI self.lSRC = self.lsr + self.lMI self.lSchnupp = self.lx - self.ly - if verbose: - print("-- small MI lengths") - print(" lx = {}m, ly = {}m".format(np.round(self.lx, 4), np.round(self.ly, 4))) - #print(" lpr = {}m, lsr = {}m".format(np.round(self.lpr, 4), np.round(self.lsr),4)) - #print(" lMI = {}m, lSchnupp = {}m".format(np.round(self.lMI, 4) , self.lSchnupp)) - print(" lSchnupp = {}m".format(np.round(self.lSchnupp,4))) - print(" lPRC = {}m, lSRC= {}m".format(self.lPRC, self.lSRC)) + self.compute_derived_resonances(kat) + + def compute_derived_resonances(self, kat): + self.fsrX = 0.5 * clight / float(kat.LX.L) + self.fsrY = 0.5 * clight / float(kat.LY.L) + self.fsrPRC = 0.5 * clight / self.lPRC + self.fsrSRC = 0.5 * clight / self.lSRC + self.f1_PRC = 3.5 * self.fsrPRC + + def lengths_status(self, kat): + print(" .--------------------------------------------------.") + print("| - arm length: |") + print("| Lx = {:11.7}m, Ly = {:11.7}m |".format(float(kat.LX.L), float(kat.LY.L))) + print("| - small MI and recycling lengths: | ") + print("| lx = {:11.7}m, ly = {:11.7}m |".format(self.lx, self.ly)) + print("| lpr = {:11.7}m, lsr = {:11.7}m |".format(self.lpr, self.lsr)) + print("| lMI = {:11.7}m, lSchnupp = {:11.5}m |".format(self.lMI, self.lSchnupp)) + print("| lPRC = {:11.7}m, lSRC = {:11.7}m |".format(self.lPRC, self.lSRC)) + print("+---------------------------------------------------+") + print("| - associated cavity frequencies [Hz]: |") + print("| fsrx = {:11.8}, fsry = {:11.8} |".format(self.fsrX, self.fsrY)) + print("| fsrPRC = {:11.8}, fsrSRC = {:11.8} |".format(self.fsrPRC, self.fsrSRC)) + print("| f1_PRC = {:11.8} |".format(self.f1_PRC)) + print("| f1 = {:11.8}, f2 = {:11.9} |".format(self.f1, self.f2)) + print(" `--------------------------------------------------'") def get_tunings(self, kat): self.tunings["maxtem"] = kat.maxtem @@ -208,36 +230,36 @@ class aLIGO(object): def apply_lock_feedback(self, kat, out): tuning = self.get_tunings(kat) - if "ETMX_lock" in out.keys(): + if "ETMX_lock" in out.ylabels: tuning["ETMX"] += float(out["ETMX_lock"]) else: print(" ** Warning: could not find ETMX lock") - if "ETMY_lock" in out.keys(): + if "ETMY_lock" in out.ylabels: tuning["ETMY"] += float(out["ETMY_lock"]) else: print(" ** Warning: could not find ETMY lock") - if "PRCL_lock" in out.keys(): + if "PRCL_lock" in out.ylabels: tuning["PRM"] += float(out["PRCL_lock"]) else: print(" ** Warning: could not find PRCL lock") - if ("MICH_lock" in out.keys()) and ("ITMY_lock" in out.keys()): + if ("MICH_lock" in out.ylabels) and ("ITMY_lock" in out.ylabels): tuning["ITMX"] += float(out["MICH_lock"]) tuning["ITMY"] += float(out["ITMY_lock"]) else: print(" ** Warning: could not find MICH (ITMY) lock") - if "SRCL_lock" in out.keys(): + if "SRCL_lock" in out.ylabels: tuning["SRM"] += float(out["SRCL_lock"]) else: print(" ** Warning: could not find SRCL lock") self.set_tunings(kat, tuning) - def pretune(self, _kat, pretune_precision=1.0e-4): + def pretune(self, _kat, pretune_precision=1.0e-4, verbose=False): print("-- pretuning interferometer to precision {0:2g} deg = {1:2g} m".format(pretune_precision, pretune_precision*_kat.lambda0/360.0)) kat=_kat.deepcopy() #_kat.ITMX.phi=0.0 #_kat.ITMY.phi=0.0 - print(" scanning X arm (maximising power)") + vprint(verbose, " scanning X arm (maximising power)") kat1 = kat.deepcopy() make_transparent(kat1,["PRM","SRM"]) make_transparent(kat1,["ITMY", "ETMY"]) @@ -245,10 +267,10 @@ class aLIGO(object): phi, precision = self.scan_to_precision(kat1, self.preARMX, pretune_precision) phi=round(phi/pretune_precision)*pretune_precision phi=round_to_n(phi,5) - print(" found max/min at: {} (precision = {:2g})".format(phi, precision)) + vprint(verbose, " found max/min at: {} (precision = {:2g})".format(phi, precision)) self.preARMX.apply_tuning(_kat,phi) - print(" scanning Y arm (maximising power)") + vprint(verbose, " scanning Y arm (maximising power)") kat = _kat.deepcopy() make_transparent(kat,["PRM","SRM"]) make_transparent(kat,["ITMX", "ETMX"]) @@ -256,34 +278,35 @@ class aLIGO(object): phi, precision = self.scan_to_precision(kat, self.preARMY, pretune_precision) phi=round(phi/pretune_precision)*pretune_precision phi=round_to_n(phi,5) - print(" found max/min at: {} (precision = {:2g})".format(phi, precision)) + vprint(verbose, " found max/min at: {} (precision = {:2g})".format(phi, precision)) self.preARMY.apply_tuning(_kat,phi) - print(" scanning MICH (minimising power)") + vprint(verbose, " scanning MICH (minimising power)") kat = _kat.deepcopy() make_transparent(kat,["PRM","SRM"]) phi, precision = self.scan_to_precision(kat, self.preMICH, pretune_precision, minmax="min", precision=30.0) phi=round(phi/pretune_precision)*pretune_precision phi=round_to_n(phi,5) - print(" found max/min at: {} (precision = {:2g})".format(phi, precision)) + vprint(verbose, " found max/min at: {} (precision = {:2g})".format(phi, precision)) self.preMICH.apply_tuning(_kat,phi, add=True) - print(" scanning PRCL (maximising power)") + vprint(verbose, " scanning PRCL (maximising power)") kat = _kat.deepcopy() make_transparent(kat,["SRM"]) phi, precision = self.scan_to_precision(kat, self.prePRCL, pretune_precision) phi=round(phi/pretune_precision)*pretune_precision phi=round_to_n(phi,5) - print(" found max/min at: {} (precision = {:2g})".format(phi, precision)) + vprint(verbose, " found max/min at: {} (precision = {:2g})".format(phi, precision)) self.prePRCL.apply_tuning(_kat,phi) - print(" scanning SRCL (maximising carrier power, then adding 90 deg)") + vprint(verbose, " scanning SRCL (maximising carrier power, then adding 90 deg)") kat = _kat.deepcopy() phi, precision = self.scan_to_precision(kat, self.preSRCL, pretune_precision, phi=0) phi=round(phi/pretune_precision)*pretune_precision phi=round_to_n(phi,4)-90.0 - print(" found max/min at: {} (precision = {:2g})".format(phi, precision)) + vprint(verbose, " found max/min at: {} (precision = {:2g})".format(phi, precision)) self.preSRCL.apply_tuning(_kat,phi) + print(" ... done") def scan_to_precision(self, kat, DOF, pretune_precision, minmax="max", phi=0.0, precision=60.0): while precision>pretune_precision*DOF.scale: @@ -306,34 +329,34 @@ class aLIGO(object): Pin = float(kat.L0.P) tunings = self.get_tunings(kat) - print(" .------------------------------------------------------.") - print(" | pretuned for maxtem = {:4} (-1 = 'off') |".format(tunings["maxtem"])) + _maxtemStr = "{:3}".format(tunings["maxtem"]) + if tunings["maxtem"] == -1: + _maxtemStr="off" + print(" .--------------------------------------------------.") + print(" | pretuned for maxtem = {}, phase = {:2} |".format(_maxtemStr, int(kat.phase))) keys_t = list(tunings.keys()) keys_t.remove("maxtem") - print(" .------------------------------------------------------.") - print(" | port power[W] pow. ratio | optics tunings |") - print(" +----------------------------|-------------------------+") + print(" .--------------------------------------------------.") + print(" | port power[W] pow. ratio | optics tunings |") + print(" +----------------------------|---------------------+") idx_p = 0 idx_t = 0 - run_p = True - run_t = True - while (run_p or run_t): + while (idx_p < len(pretune_DOFs) or idx_t < len(keys_t)): if idx_p < len(pretune_DOFs): p = pretune_DOFs[idx_p] - print(" | {:5}: {:8.3g} {:8.3g} |".format(p.name, float(out[p.port.name]), float(out[p.port.name])/Pin),end="") + print(" | {:5}: {:9.4g} {:9.4g} |".format(p.name, float(out[p.port.name]), float(out[p.port.name])/Pin),end="") idx_p +=1 else: print(" | |", end="") - run_p = False if idx_t < len(keys_t): t=keys_t[idx_t] - print(" {:5}: {:9.3g} |".format(t, float(self.tunings[t]))) + print(" {:5}: {:9.3g} |".format(t, float(self.tunings[t]))) idx_t +=1 else: - print(" |") - run_t = False - print(" `------------------------------------------------------'") - + print(" |") + print(" `--------------------------------------------------'") + + # probably extra and can be removed def power_ratios(self, _kat): kat = _kat.deepcopy() kat.verbose = False @@ -392,12 +415,49 @@ class aLIGO(object): plt.tight_layout() plt.show(block=0) - def find_DC_offset(self, _kat, AS_power, precision=1e-4): + def set_DC_offset(self, _kat, DCoffset=None, verbose=False): + if DCoffset: + self.DCoffset=DCoffset + print("-- applying user-defined DC offset:") + pretuning = self.get_tunings(_kat) + pretuning["ETMY"] += self.DCoffset + pretuning["ETMX"] -= self.DCoffset + self.set_tunings(_kat, pretuning) + kat = _kat.deepcopy() + sigStr = self.AS_DC.signal(kat) + signame = self.AS_DC.signal_name(kat) + kat.parseCommands(sigStr) + kat.noxaxis=True + out = kat.run() + self.DCoffsetW=float(out[signame]) + else: + # Finding light power in AS port (mostly due to RF sidebands now + kat = _kat.deepcopy() + sigStr = self.AS_DC.signal(kat) + signame = self.AS_DC.signal_name(kat) + kat.parseCommands(sigStr) + kat.noxaxis=True + out = kat.run() + print("-- adjusting DCoffset based on light in dark port:") + waste_light = round(float(out[signame]),1) + print(" waste light in AS port of {:2} W".format(waste_light)) + kat_lock = _kat.deepcopy() + self.find_DC_offset(kat_lock, 2*waste_light) + pretuning = self.get_tunings(kat_lock) + pretuning["ETMY"] += self.DC_offset + pretuning["ETMX"] -= self.DC_offset + self.set_tunings(_kat, pretuning) + self.DCoffset_meter = self.DCoffset / 360.0 * _kat.lambda0 + vprint(verbose, " DCoffset = {:6.4} deg ({:6.4}m)".format(self.DCoffset, self.DCoffset_meter)) + vprint(verbose, " at dark port power: {:6.4}W".format(self.DCoffsetW)) + + + def find_DC_offset(self, _kat, AS_power, precision=1e-4, verbose=False): """ Returns the DC offset of DARM that corrponds to the specified power in the AS power. """ - print("-- finding DC offset for AS power of {:3g} W".format(AS_power)) + vprint(verbose, " finding DC offset for AS power of {:3g} W".format(AS_power)) kat = _kat.deepcopy() kat.verbose = False kat.noxaxis = True @@ -413,8 +473,10 @@ class aLIGO(object): #print(out[self.AS_DC.name]-AS_power) return np.abs(out[self.AS_DC.name]-AS_power) - out=fmin(powerDiff,0,xtol=precision,ftol=1e-3,args=(kat, Xphi, Yphi, AS_power)) - print(" DC offset for AS_DC={} W is: {}".format(AS_power, out[0])) + vprint(verbose, " starting peak search...") + out=fmin(powerDiff,0,xtol=precision,ftol=1e-3,args=(kat, Xphi, Yphi, AS_power), disp=verbose) + vprint(verbose, " ... done") + vprint(verbose, " DC offset for AS_DC={} W is: {}".format(AS_power, out[0])) self.DCoffset = round(out[0],6) self.DCoffsetW = AS_power return self.DCoffset @@ -445,42 +507,47 @@ class aLIGO(object): return code1 - def generate_lock_block(self, _kat, _gains=None, _accuracies=None, verbose=False): + def generate_lock_block(self, _kat, _gains=None, _accuracies=None, verbose=True): """ - gains: optical gain is in W per rad + gains: optical gain is in W per deg accuracies: error signal threshold in W - rms, estimated loop noise rms m - to compute accuracies from rms, we convert - rms to radians as rms_rad = rms * 2 pi/lambda - and then multiply by the optical gain. """ kat = _kat.deepcopy() - if _gains == None: - ogDARM = optical_gain(kat, self.DARM, self.DARM) - ogCARM = optical_gain(kat, self.CARM, self.CARM) - ogPRCL = optical_gain(kat, self.PRCL, self.PRCL) - ogMICH = optical_gain(kat, self.MICH, self.MICH) - ogSRCL = optical_gain(kat, self.SRCL, self.SRCL) - if verbose: - print("-- optical gains:") - print(" DARM: {}".format(ogDARM)) - print(" CARM: {}".format(ogCARM)) - print(" PRCL: {}".format(ogPRCL)) - print(" MICH: {}".format(ogMICH)) - print(" SRCL: {}".format(ogSRCL)) - gains = [ ogDARM, ogCARM, ogPRCL, ogMICH, ogSRCL] + # optical gains in W/rad + ogDARM = optical_gain(kat, self.DARM, self.DARM) + ogCARM = optical_gain(kat, self.CARM, self.CARM) + ogPRCL = optical_gain(kat, self.PRCL, self.PRCL) + ogMICH = optical_gain(kat, self.MICH, self.MICH) + ogSRCL = optical_gain(kat, self.SRCL, self.SRCL) + + if _gains == None: + # manually tuning relative gains + gainExtra = [0.5, 0.005, 1.0, 0.5, 0.025] + factor = -1.0 * 180 / math.pi # convert from rad/W to -1 * deg/W + gainDARM = round_to_n(gainExtra[0] * factor / ogDARM, 2) # manually tuned + gainCARM = round_to_n(gainExtra[1] * factor / ogCARM, 2) # factor 0.005 for better gain hirarchy with DARM + gainPRCL = round_to_n(gainExtra[2] * factor / ogPRCL, 2) # manually tuned + gainMICH = round_to_n(gainExtra[3] * factor / ogMICH, 2) # manually tuned + gainSRCL = round_to_n(gainExtra[4] * factor / ogSRCL, 2) # gain hirarchy with MICH + gains = [ gainDARM, gainCARM, gainPRCL, gainMICH, gainSRCL] + else: gains = _gains.copy() - rms = [1e-13, 1e-12, 1e-11, 1e-11, 1e-11] - factor = 2.0 * math.pi / kat.lambda0 + # rms: loop accuracies in meters (manually tuned for the loops to work + # with the default file) + # to compute accuracies from rms, we convert + # rms to radians as rms_rad = rms * 2 pi/lambda + # and then multiply by the optical gain. + rms = [1e-13, 1e-13, 1e-12, 1e-11, 50e-11] # default accuracies in meters + factor = 2.0 * math.pi / kat.lambda0 # convert from m to radians if _accuracies == None: - accDARM = round_to_n(np.abs(factor * rms[0] * gains[0]),2) - accCARM = round_to_n(np.abs(factor * rms[1] * gains[1]),2) * 0.1 # manually tuned - accPRCL = round_to_n(np.abs(factor * rms[2] * gains[2]),2) * 0.1 # manually tuned - accMICH = round_to_n(np.abs(factor * rms[3] * gains[3]),2) - accSRCL = round_to_n(np.abs(factor * rms[4] * gains[4]),2) * 50.0 # manually tuned + accDARM = round_to_n(np.abs(factor * rms[0] * ogDARM),2) + accCARM = round_to_n(np.abs(factor * rms[1] * ogCARM),2) + accPRCL = round_to_n(np.abs(factor * rms[2] * ogPRCL),2) + accMICH = round_to_n(np.abs(factor * rms[3] * ogMICH),2) + accSRCL = round_to_n(np.abs(factor * rms[4] * ogSRCL),2) acc = [accDARM, accCARM, accPRCL, accMICH, accSRCL] else: acc = _accuracies.copy() @@ -500,21 +567,12 @@ class aLIGO(object): set SRCL_err {} re func DARM_err = $AS_f2_I_re - {} """.format(nameDARM, nameCARM, namePRCL, nameMICH, nameSRCL, self.DCoffsetW) - - factor = 0.4 * -1.0 * 180 / math.pi # 0.2 because of multiple locks cross talk - gainDARM = round_to_n(factor / ogDARM, 2) - gainCARM = round_to_n(0.01 * factor / ogCARM, 2) # factor 0.01 for better gain hirarchy - gainPRCL = round_to_n(2.0 * factor / ogPRCL, 2) # manually tuned - gainMICH = round_to_n(1.0 * factor / ogMICH, 2) # manually tuned - gainSRCL = round_to_n(0.05 * factor / ogSRCL, 2) # gain hirrchy with MICH - code2 = """ - lock DARM_lock $DARM_err {} {} - lock CARM_lock $CARM_err {} {} - lock PRCL_lock $PRCL_err {} {} - lock MICH_lock $MICH_err {} {} - lock SRCL_lock $SRCL_err {} {} - """.format(gainDARM, acc[0], gainCARM, acc[1], gainPRCL, acc[2], gainMICH, acc[3], gainSRCL, acc[4]) + code2 = """lock DARM_lock $DARM_err {:8.2} {:8.2} +lock CARM_lock $CARM_err {:8.2g} {:8.2g} +lock PRCL_lock $PRCL_err {:8.2g} {:8.2g} +lock MICH_lock $MICH_err {:8.2g} {:8.2g} +lock SRCL_lock $SRCL_err {:8.2g} {:8.2g}""".format(gains[0], acc[0], gains[1], acc[1], gains[2], acc[2], gains[3], acc[3], gains[4], acc[4]) code3 = """ noplot ITMY_lock @@ -540,6 +598,41 @@ class aLIGO(object): ########################################################################### %%% FTend locks """ + factor1 = 2.0 * math.pi / 360.0 + factor2 = 2.0 * math.pi / kat.lambda0 + factor3 = 360.0 / kat.lambda0 + factor4 = -1.0 * 180 / math.pi + + if verbose: + print(" .--------------------------------------------------.") + print(" | Parameters for locks: |") + print(" +--------------------------------------------------+") + print(" | -- optical gains [W/rad], [W/deg] and [W/m]: |") + print(" | DARM: {:12.5}, {:12.5}, {:12.5} |".format(ogDARM, ogDARM*factor1, ogDARM*factor2)) + print(" | CARM: {:12.5}, {:12.5}, {:12.5} |".format(ogCARM, ogCARM*factor1, ogCARM*factor2)) + print(" | PRCL: {:12.5}, {:12.5}, {:12.5} |".format(ogPRCL, ogPRCL*factor1, ogPRCL*factor2)) + print(" | MICH: {:12.5}, {:12.5}, {:12.5} |".format(ogMICH, ogMICH*factor1, ogMICH*factor2)) + print(" | SRCL: {:12.5}, {:12.5}, {:12.5} |".format(ogSRCL, ogSRCL*factor1, ogSRCL*factor2)) + print(" +--------------------------------------------------+") + print(" | -- defult loop accuracies [deg], [m] and [W]: |") + print(" | DARM: {:12.6}, {:12.6}, {:12.6} |".format(factor3*rms[0], rms[0], np.abs(rms[0]*ogDARM*factor2))) + print(" | CARM: {:12.6}, {:12.6}, {:12.6} |".format(factor3*rms[1], rms[1], np.abs(rms[1]*ogCARM*factor2))) + print(" | PRCL: {:12.6}, {:12.6}, {:12.6} |".format(factor3*rms[2], rms[2], np.abs(rms[2]*ogPRCL*factor2))) + print(" | MICH: {:12.6}, {:12.6}, {:12.6} |".format(factor3*rms[3], rms[3], np.abs(rms[3]*ogMICH*factor2))) + print(" | SRCL: {:12.6}, {:12.6}, {:12.6} |".format(factor3*rms[4], rms[4], np.abs(rms[4]*ogSRCL*factor2))) + print(" +--------------------------------------------------+") + print(" | -- extra gain factors (factor * 1/optical_gain): |") + print(" | DARM: {:5.4} * {:12.6} = {:12.6} |".format(gainExtra[0],factor4/ogDARM, gainExtra[0]*factor4/ogDARM)) + print(" | CARM: {:5.4} * {:12.6} = {:12.6} |".format(gainExtra[1],factor4/ogCARM, gainExtra[1]*factor4/ogCARM)) + print(" | PRCL: {:5.4} * {:12.6} = {:12.6} |".format(gainExtra[2],factor4/ogPRCL, gainExtra[2]*factor4/ogPRCL)) + print(" | MICH: {:5.4} * {:12.6} = {:12.6} |".format(gainExtra[3],factor4/ogMICH, gainExtra[3]*factor4/ogMICH)) + print(" | SRCL: {:5.4} * {:12.6} = {:12.6} |".format(gainExtra[4],factor4/ogSRCL, gainExtra[4]*factor4/ogSRCL)) + print(" +--------------------------------------------------+") + print(" | -- lock commands used: |") + for l in code2.splitlines(): + print (" | {:49}|".format(l)) + print(" `--------------------------------------------------'") + return "".join([code1, code2, code3]) # --------------------------------------------------------------------------------- @@ -737,7 +830,7 @@ def make_transparent(kat, _components): raise pkex.BasePyKatException("Cannot find component {}".format(components)) return kat -def reconnect_nodes(kat, component1, idx1, node_name): +def reconnect_nodes(kat, component1, idx1, node_name, verbose=False): c_string = component1.getFinesseText() c = c_string[0].split() new_string = " ".join(c[:-2]) @@ -746,22 +839,22 @@ def reconnect_nodes(kat, component1, idx1, node_name): nodes[1] = c[-1] nodes[idx1]=node_name new_string = new_string + " " + nodes[0] + " " + nodes[1] - #print(" new string ='{}'".format(new_string)) + vprint(verbose, " new string ='{}'".format(new_string)) kat.parseCommands(new_string) -def remove_commands(kat, _commands): +def remove_commands(kat, _commands, verbose=False): commands=make_list_copy(_commands) # removing commands for o in kat.commands.values(): if o.name in commands: o.remove() commands = [c for c in commands if c != o.name] - #print(' {} removed'.format(o)) + vprint(verbose, ' {} removed'.format(o)) if len(commands) != 0: raise pkex.BasePyKatException("Cannot find command(s) {}".format(commands)) return kat -def remove_components(kat, _components, component_in=None, component_out=None): +def remove_components(kat, _components, component_in=None, component_out=None, verbose=False): components=make_list_copy(_components) if kat.components[components[-1]].nodes[1]: node_in = kat.components[components[-1]].nodes[1].name @@ -773,7 +866,7 @@ def remove_components(kat, _components, component_in=None, component_out=None): if o.name in components: o.remove() components = [c for c in components if c != o.name] - #print(' {} removed'.format(o)) + vprint(verbose, ' {} removed'.format(o)) if len(components) != 0: raise pkex.BasePyKatException("Cannot find component(s) {}".format(components)) # reconnecting nodes if requested @@ -837,7 +930,7 @@ def optical_gain(_kat, DOF_sig, DOF_det, f=10.0): kat.noxaxis = True kat.parseCommands("yaxis lin abs:deg") out = kat.run() - return np.real(out[_detName]) + return float(np.real(out[_detName])) def find_peak(out, detector, minmax='max', debug=False): """ @@ -852,11 +945,12 @@ def find_peak(out, detector, minmax='max', debug=False): find_peak(out, "pdout", minmax='min') """ stepsize = out.x[1]-out.x[0] - print(" stepsize (precision) of scan: {0:g}".format(stepsize)) + if debug: + print(" stepsize (precision) of scan: {0:g}".format(stepsize)) _max, _min = peak.peakdetect( out[detector],out.x, 1) - if debug==True: + if debug: plt.figure() plt.plot(out.x,out[detector]) print("max: ") @@ -877,7 +971,7 @@ def find_peak(out, detector, minmax='max', debug=False): else: raise pkex.BasePyKatException("maxmin must be 'max' or 'min'") - if debug==True: + if debug: plt.plot(X_out,Y_out,'o') plt.xlabel('tuning [deg]') plt.ylabel('{0} output'.format(detector)) @@ -900,3 +994,8 @@ def round_to_n(x, n): power = -int(math.floor(math.log10(abs(x)))) + (n - 1) factor = (10 ** power) return round(x * factor) / factor + + +def vprint(verbose, printstr): + if verbose: + print(printstr)