Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • nloqo/snlo-helper
1 result
Show changes
Commits on Source (2)
......@@ -28,14 +28,12 @@ Install it executing `pip install -e .` in this folder or via `pip install git+h
Here is a small snippet how to do a 2D mix of long pulses:
```
from snlohelper import snlo
from snlohelper.main_window import MainWindow
snlo.utils.set_screenfactors()
sim = snlo.TwoDMixLP() # create a class for 2D mix
sim.open() # click the corresponding button to open 2D mix
sim.configure({"Wavelengths (nm)": [1064.5, None, None]}) # configure it
result = sim.run_and_read() # run it
mw = MainWindow()
mix = mw.open_two_d_mix_lp()
mix.configure({"Wavelengths (nm)": [1064.5, None, None]})
result = mix.run_and_read()
print(result)
```
......@@ -47,10 +45,10 @@ For more examples see the `examples` folder.
* The `main_window.MainWindow` class manages the main window.
* For several functions exists a module containing a class, which in turn allows to configure the function, to run the calculation, and to extract the result.
1. You start that class, for example `mix = two_d_mix_lp.TwoDMixLp()` or `mix = MainWindow().open_function("2D-Mix-LP")`.
2. You can configure it giving a configuration dictionary (the keys correspond to the names) with `mix.configure({"Wavelengths": [1064, None, None]})`
2. You can configure it giving a configuration dictionary (the keys correspond to the names) with `mix.configure({"Wavelengths": [1064, None, None]})`. If a value is `None`, it won't be changed.
3. You can run it with `mix.run()`
4. With `results = mix.read_results()` you can extract the resulting text.
5. With `result_dict = mix.interpret_results(results)` you get a dictionary of the data
5. With `result_dict = mix.interpret_results(results)` you get a dictionary of the result data
6. There are convenience methods like `mix.run_and_read` which runs and returns the dictionary, or even `mix.configure_run_read`, which does all of above steps in one.
......
"""
Example on how to use the SNLO data files.
"""
import numpy as np
import time
from typing import cast
import matplotlib.pyplot as plt
import matplotlib.ticker as tic
import pyautogui as gui
import analysis.modules_JFK as m
from snlohelper import scale, import_snlo_file
from scipy import constants as cs
from scipy.optimize import curve_fit
from snlohelper.utils import scale
from snlohelper.import_snlo_file import import_snlo_file
def gauss(x, x0, a, sigma):
"""Gaussian function"""
return a * np.exp(-((x - x0) ** 2) / (2 * sigma**2))
def plotdata(data, xScale=1, yScale=1):
"""Returns the x and y components of a two dimensional list as individual lists, e.g., for
plotting. Optional linear scale factors as additional commands"""
xValues = []
yValues = []
for i in range(len(data)):
xValues.append(xScale * data[i][0])
yValues.append(yScale * data[i][1])
return xValues, yValues
def gaussian_fit(data, print_output=False):
"""performs Gaussian fit (position, amplitude, standard deviation), returns popt, sdev, serr,
pcov"""
# arguments of gauss-function: gauss(x, x0, a, sigma)
x, y = plotdata(data)
# find peak position
peak_pos = x[list(y).index(max(y))]
try:
popt, pcov = curve_fit(gauss, x, y, p0=[peak_pos, 1, 1])
except RuntimeError:
print("fit failed!")
popt, pcov = [0, 0, 0], np.zeros((3, 3)).tolist()
# covariance matrix: diagonal elements are the variances, hence, the square root is the
# standard deviation
sdev = np.sqrt(abs(pcov.diagonal()).tolist())
# standard errors are sd/sqrt(n) with the sample size n
serr = sdev / (np.sqrt(len(data)))
return popt, sdev, serr, pcov
def plot_options(
fig,
ax,
xlabel=None,
ylabel=None,
font_size=11,
ticks=["auto", "auto"],
image_width=10,
aspect_ratio=cs.golden,
dpi=200,
):
"""
sets plot options just like in Mathematica
:param fig: figure object from pyplot (necessary)
:param ax: axes object from pyplot (necessary)
:param xlabel: x-axis label (string or None)
:param ylabel: y-axis label (string or None)
:param font_size: font size (number, standard=11)
:param ticks: custom or auto ticks (list of x and y: 'auto' or major tick increment)
:param image_width: width of the image in cm (number, standard=10)
:param aspect_ratio: aspect ratio of the image (number, standard=golden ratio)
Parameters
----------
dpi : dpi for displaying in jupyterlab (standard = 200)
"""
# set size and aspect ratio
fig.set_size_inches(image_width / 2.54, image_width / 2.54 / aspect_ratio)
fig = plt.gcf()
plt.rcParams["font.family"] = "Arial"
fig.set_dpi(dpi) # only for display in jupyterlab!
fig.patch.set_facecolor("white") # type: ignore
# plt.style.use('classic')
ax.tick_params(
axis="both", which="major", labelsize=font_size, right=True, top=True, direction="in"
)
ax.tick_params(
axis="both", which="minor", labelsize=font_size - 2, right=True, top=True, direction="in"
)
# custom major ticks
if ticks[0] == "auto":
ax.xaxis.set_major_locator(tic.AutoLocator())
else:
ax.xaxis.set_major_locator(tic.MultipleLocator(ticks[0]))
if ticks[1] == "auto":
ax.yaxis.set_major_locator(tic.AutoLocator())
else:
ax.yaxis.set_major_locator(tic.MultipleLocator(ticks[1]))
# activate automatic minor ticks
ax.xaxis.set_minor_locator(tic.AutoMinorLocator())
ax.yaxis.set_minor_locator(tic.AutoMinorLocator())
# changes fontsize of the labels
ax.set_xlabel(xlabel, color="black", fontsize=font_size)
ax.set_ylabel(ylabel, color="black", fontsize=font_size)
# reduce tick lengths
ax.tick_params(axis="both", which="minor", length=2)
ax.tick_params(axis="both", which="major", length=3)
def get_spectr(
......@@ -31,7 +144,7 @@ def get_spectr(
# fit idler duration
x = 1e9 * id_beam.T[0] # ns
y = id_beam.T[1]
idl = m.gaussian_fit(np.array([x, y]).T, False)[0]
idl = gaussian_fit(np.array([x, y]).T, False)[0]
fwhm_ns_idl = abs(2 * np.sqrt(2 * np.log(2)) * idl[2])
x_lists = [x.copy()]
y_lists = [y.copy()]
......@@ -39,7 +152,7 @@ def get_spectr(
# fit signal duration
x = 1e9 * sig_beam.T[0] # ns
y = sig_beam.T[1]
sig = m.gaussian_fit(np.array([x, y]).T, False)[0]
sig = gaussian_fit(np.array([x, y]).T, False)[0]
fwhm_ns_sig = abs(2 * np.sqrt(2 * np.log(2)) * sig[2])
x_lists.append(x)
y_lists.append(y)
......@@ -47,7 +160,7 @@ def get_spectr(
# fit pump duration
x = 1e9 * pmp_beam.T[0] # ns
y = pmp_beam.T[1]
pmp = m.gaussian_fit(np.array([x, y]).T, False)[0]
pmp = gaussian_fit(np.array([x, y]).T, False)[0]
fwhm_ns_pmp = abs(2 * np.sqrt(2 * np.log(2)) * pmp[2])
x_lists.append(x)
y_lists.append(y)
......@@ -59,7 +172,7 @@ def get_spectr(
titles = "idler (Red1)", "signal (Red2)", "pump (Blue)"
colors = "red", "green", "blue"
for i in range(len(ax)):
m.plot_options(
plot_options(
fig, ax[i], xlabel="time (ns)", image_width=15, aspect_ratio=3
)
ax[i].plot(x_lists[i], y_lists[i], ".", color=colors[i])
......@@ -67,10 +180,10 @@ def get_spectr(
x_fit = np.arange(min(x_lists[i]), max(x_lists[i]), 0.1)
ax[i].plot(x_fit, m.gauss(x_fit, *fits[i]), "-", color=colors[i])
ax[i].plot(x_fit, gauss(x_fit, *fits[i]), "-", color=colors[i])
ax[i].text(0, 0, f"FWHM\n{fwhms[i]:.1f}ns", ha="center", color=colors[i])
# ax[i].set_xlim([min(x_lists[i]), max(x_lists[i])])
m.plot_options(
plot_options(
fig,
ax[0],
image_width=15,
......@@ -87,9 +200,9 @@ def get_spectr(
y_sig = spectr.T[2]
y_pmp = spectr.T[3]
idl = cast(list[float], m.gaussian_fit(np.array([x, y_idl]).T, False)[0])
sig = cast(list[float], m.gaussian_fit(np.array([x, y_sig]).T, False)[0])
pmp = cast(list[float], m.gaussian_fit(np.array([x, y_pmp]).T, False)[0])
idl = cast(list[float], gaussian_fit(np.array([x, y_idl]).T, False)[0])
sig = cast(list[float], gaussian_fit(np.array([x, y_sig]).T, False)[0])
pmp = cast(list[float], gaussian_fit(np.array([x, y_pmp]).T, False)[0])
fwhm_spec_idl = abs(2 * np.sqrt(2 * np.log(2)) * idl[2])
fwhm_spec_sig = abs(2 * np.sqrt(2 * np.log(2)) * sig[2])
......@@ -105,7 +218,7 @@ def get_spectr(
titles = "idler (Red1)", "signal (Red2)", "pump (Blue)"
colors = "red", "green", "blue"
for i in range(len(ax)):
m.plot_options(
plot_options(
fig, ax[i], xlabel="detuning (MHz)", image_width=15, aspect_ratio=3
)
ax[i].plot(x, y_lists[i], ".", color=colors[i])
......@@ -113,10 +226,10 @@ def get_spectr(
x_fit = np.arange(min(x), max(x), 0.1)
ax[i].plot(x_fit, m.gauss(x_fit, *fits[i]), "-", color=colors[i])
ax[i].plot(x_fit, gauss(x_fit, *fits[i]), "-", color=colors[i])
ax[i].text(0, 0, f"FWHM\n{fwhms[i]:.1f}MHz", ha="center", color=colors[i])
ax[i].set_xlim([-2 * fwhms[i], 2 * fwhms[i]])
m.plot_options(
plot_options(
fig,
ax[0],
image_width=15,
......
from snlohelper import snlo
from snlohelper.main_window import MainWindow
snlo.utils.set_screenfactors()
sim = snlo.TwoDMixLP()
sim.open()
sim.configure({"Wavelengths (nm)": [1064.5, None, None]})
result = sim.run_and_read()
mw = MainWindow()
mix = mw.open_two_d_mix_lp()
mix.configure({"Wavelengths (nm)": [1064.5, None, None]})
result = mix.run_and_read()
print(result)
"""
Example of a simulation using SNLO
A hash followed by two or more percent signs (e.g. "# %%") indicates cells to execute in ipython.
1. Start SNLO (do not move it!)
2. Execute the cells.
If a cell starts with `alt_tab`, SNLO should be the program run last
"""
# %%
# Imports
import matplotlib.pyplot as plt
import numpy as np
from scipy import constants as cs
from snlohelper.main_window import MainWindow
from snlohelper import utils
# open the class for the main window
mw = MainWindow()
# %%
"Hard facts"
"""
Values which are given by physics or by the whole setup
"""
# Wavelengths etc.
signal_wl = 3534 / 3 # nm == 1178 nm
pump_wl = 532 # nm
temperature = 300 # K
# Result of qmix for the crystal (BBO)
"""
1178.0(o)+ 532.0(o)= 366.5(e)
Walkoff [mrad] = 0.00 0.00 69.90
Phase velocities = c/ 1.652 1.674 1.667
Group velocities = c/ 1.672 1.722 1.769
GrpDelDisp(fs^2/mm) = 32.7 136.0 229.4
At theta = 29.8 deg.
Deff = 2.03E0 pm/V
S_o × L^2 = 2.35E7 Watt
Crystal ang. tol.×L = 0.31 mrad°cm
Temperature range×L = 17.39 K°cm
Mix accpt ang×L = 1.02 0.45 mrad°cm
Mix accpt bw×L = 310.43 640.98 GHz°cm
"""
upconverted_wl = 366.5 # resulting wavelength
theta = 29.8
Deff = 2.03e0
walkoff = (0, 0, 69.9) # angles in mrad
length = 12 # mm
# %%%
# calculate the refractive indices
def get_n():
utils.alt_tab()
ref = mw.open_refractive_index()
s, _ = ref.refractive_indices("Ab", Temperature=temperature, theta=theta, Wavelength=signal_wl)
p, _ = ref.refractive_indices(Wavelength=pump_wl)
_, u = ref.refractive_indices(Wavelength=upconverted_wl)
ref.close()
return (s, p, u)
n = get_n()
# %%%
# Laser system
# fwhm pulse duration in ns
signal_ns = 3.3
pump_ns = 6
# fwhm beam diameter at entry face in mm (for elliptical 1st in walkoff, second orthogonal)
signal_mm = 1.3647e-1
signal_curv_mm = 3.4981e2
pump_mm = "0.914 0.397"
pump_curv_mm = "-1.7e3 -3.34E3"
upconverted_mm = 0.07788
upconverted_curv_mm = 7.4392e2
# grid size: length, width_walkoff, height_orthogonal, all in mm
grid = (length, 2.5, 1)
# %%
"Simulation settings"
signal_photons = 100_000
pump_E = 1e-9 # in J
# Calculate
signal_E = signal_photons * cs.h * cs.c / signal_wl / 1e-9 # in J
walkoff_offset = (0, 0, walkoff[2] * -1e-3 * length / 2) # to have overlap in the center
# %%%
# Configure SNLO initially
utils.alt_tab()
mix = mw.open_two_d_mix_lp()
# start configuration: set all values in order to have a predefined configuration
mix.configure({
"Wavelengths (nm)": (signal_wl, pump_wl, upconverted_wl),
"Indexes of refraction": n,
"Phases at input (rad)": [0.0, 0.0, 0.0],
"Input face reflectivity (0-1)": [0.0, 0.0, 0.0],
"Output face reflectivity (0-1)": [0.0, 0.0, 0.0],
"Crystal loss (1/mm)": [0.0, 0.0, 0.0],
"Energy/power (J or W)": (signal_E, pump_E, 0),
"Pulse duration (fwhm ns)": (signal_ns, pump_ns, 0),
"Beam diam. (fwhm mm)": (signal_mm, pump_mm, upconverted_mm),
"Supergaussian coeff.": [1.0, 1.0, 1.0],
"n2 red1 (sq cm/W)": [0.0, 0.0, 0.0],
"n2 red2 (sq cm/W)": [0.0, 0.0, 0.0],
"n2 blue (sq cm/W)": [0.0, 0.0, 0.0],
"beta red1 (cm/W)": [0.0, 0.0, 0.0],
"beta red2 (cm/W)": [0.0, 0.0, 0.0],
"beta blue (cm/W)": [0.0, 0.0, 0.0],
"Walkoff angles (mrad)": walkoff,
"Offset in wo dir. (mm)": walkoff_offset,
"Rad. curv. (mm/air)": (signal_curv_mm, pump_curv_mm, upconverted_curv_mm),
"# of integ/grid points": [30.0, 32.0, 32.0],
"Crystal/grid sizes (mm)": grid,
"Deff (pm/V)": Deff,
"Delta k (1/mm)": [0.0],
"Dist. to image (mm)": [0.0],
"# time steps": [20.0],
})
# %%
# Run simulation
# Parameters
inputs = np.linspace(1e-4, 15e-3, 20, endpoint=False)
utils.alt_tab()
output = []
for i in inputs:
print(i)
result = mix.configure_run_read({"Energy/power (J or W)": (None, i, None)})
output.append(result["Output pulse energy (mJ)"][2]) # type: ignore
utils.alt_tab()
print(output)
# %%%
# Plot most recent values
fig = plt. figure()
ax = plt.gca()
ax.plot(inputs, output, ls=":", marker="+")
ax.set_xlabel("pump energy in mJ")
ax.set_ylabel("upconversion energy in mJ")
plt.show()
[project]
name = "snlo-helper"
dynamic = ["version"]
authors = [
{name = "Benedikt Burger},
]
description = "An autoclicker to automatically configure and read SNLO."
keywords = ["SNLO", "nonlinear optics", "simulation"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Science/Research",
"Topic :: Scientific/Engineering :: Physics",
"Topic :: Utilities",
]
requires-python = ">=3.9"
dependencies = [
......
# Required python packages for the simulation
# Install all packages with `pip install -r requirements.txt`.
# To get a list of installed packages use `pip freeze`.
# General tools
matplotlib
numpy
pandas
pint
scipy
# For SNLO helper
pyautogui
pyperclip
# requires analysis.modules_JFK from the eg-labor repository.