started working on plasma

This commit is contained in:
Benoît Sierro
2021-06-30 09:37:49 +02:00
parent 2bd5c3d055
commit 9d036ae608
8 changed files with 149 additions and 29 deletions

View File

@@ -118,13 +118,13 @@ capillary_nested : int, optional
gamma: float, optional unless beta is directly provided gamma: float, optional unless beta is directly provided
nonlinear parameter in m^2 / W. Will overwrite any computed gamma parameter. nonlinear parameter in m^-1*W^-1. Will overwrite any computed gamma parameter.
effective_mode_diameter : float, optional effective_mode_diameter : float, optional
effective mode field diameter in m effective mode field diameter in m
n2 : float, optional n2 : float, optional
non linear refractive index non linear refractive index in m^2/W
A_eff : float, optional A_eff : float, optional
effective mode field area effective mode field area

View File

@@ -10,6 +10,6 @@ from .math import abs2, argclosest, span
from .physics import fiber, materials, pulse, simulate, units from .physics import fiber, materials, pulse, simulate, units
from .physics.simulate import RK4IP, new_simulation, resume_simulations from .physics.simulate import RK4IP, new_simulation, resume_simulations
from .plotting import plot_avg, plot_results_1D, plot_results_2D, plot_spectrogram from .plotting import plot_avg, plot_results_1D, plot_results_2D, plot_spectrogram
from .spectra import Pulse from .spectra import Pulse, Spectrum
from .utils.parameter import BareParams, BareConfig from .utils.parameter import BareParams, BareConfig
from . import utils, io, initialize, math from . import utils, io, initialize, math

View File

@@ -26,7 +26,8 @@ def material_dispersion(
material: str, material: str,
pressure=None, pressure=None,
temperature=None, temperature=None,
ideal=False, ideal=True,
safe=True,
): ):
"""returns the dispersion profile (beta_2) of a bulk material. """returns the dispersion profile (beta_2) of a bulk material.
@@ -41,7 +42,7 @@ def material_dispersion(
pressure : float, optional pressure : float, optional
constant pressure constant pressure
ideal : bool, optional ideal : bool, optional
whether to use the ideal gas law instead of the van der Waals equation, by default False whether to use the ideal gas law instead of the van der Waals equation, by default True
Returns Returns
------- -------
@@ -50,6 +51,9 @@ def material_dispersion(
""" """
w = units.m(wavelengths) w = units.m(wavelengths)
order = np.argsort(w)
material_dico = load_material_dico(material) material_dico = load_material_dico(material)
if ideal: if ideal:
n_gas_2 = materials.sellmeier(wavelengths, material_dico, pressure, temperature) + 1 n_gas_2 = materials.sellmeier(wavelengths, material_dico, pressure, temperature) + 1
@@ -59,12 +63,19 @@ def material_dispersion(
) )
N_0 = materials.number_density_van_der_waals(material_dico=material_dico) N_0 = materials.number_density_van_der_waals(material_dico=material_dico)
n_gas_2 = materials.sellmeier(wavelengths, material_dico) * N_1 / N_0 + 1 n_gas_2 = materials.sellmeier(wavelengths, material_dico) * N_1 / N_0 + 1
if safe:
return fiber.beta2(w, np.sqrt(n_gas_2)) disp = np.zeros(len(w))
ind = w > 0
disp[ind] = material_dispersion(
units.To.m(w[ind]), material, pressure, temperature, ideal, False
)
return disp
else:
return fiber.beta2(w[order], np.sqrt(n_gas_2[order]))[order]
def find_optimal_depth( def find_optimal_depth(
spectrum: T, w_c: np.ndarray, w0: float, material: str = "silica", max_z: float = 1.0 spectrum: T, w_c: np.ndarray, w0: float, material: str, max_z: float = 1.0
) -> tuple[T, pulse.OptimizeResult]: ) -> tuple[T, pulse.OptimizeResult]:
"""finds the optimal silica depth to compress a pulse """finds the optimal silica depth to compress a pulse
@@ -86,12 +97,26 @@ def find_optimal_depth(
float float
distance in m distance in m
""" """
silica_disp = material_dispersion(units.To.m(w_c + w0), material) w = w_c + w0
disp = np.zeros(len(w))
ind = w > (w0 / 10)
disp[ind] = material_dispersion(units.To.m(w[ind]), material)
propagate = lambda z: spectrum * np.exp(-0.5j * silica_disp * w_c ** 2 * z) propagate = lambda z: spectrum * np.exp(-0.5j * disp * w_c ** 2 * z)
integrate = lambda z: math.abs2(np.fft.ifft(propagate(z)))
def score(z): def score(z):
return 1 / np.max(math.abs2(np.fft.ifft(propagate(z)))) return -np.nansum(integrate(z) ** 6)
opti = minimize_scalar(score, bracket=(0, max_z)) # import matplotlib.pyplot as plt
return opti.x
# to_test = np.linspace(0, max_z, 200)
# scores = [score(z) for z in to_test]
# fig, ax = plt.subplots()
# ax.plot(to_test, scores / np.min(scores))
# plt.show()
# plt.close(fig)
# ama = np.argmin(scores)
opti = minimize_scalar(score, method="bounded", bounds=(0, max_z))
return propagate(opti.x), opti

View File

@@ -647,7 +647,7 @@ def PCF_dispersion(lambda_, pitch, ratio_d, w0=None, n2=None, A_eff=None):
if A_eff is None: if A_eff is None:
V_eff = pi2a / lambda_ * np.sqrt(n_co ** 2 - n_FSM2) V_eff = pi2a / lambda_ * np.sqrt(n_co ** 2 - n_FSM2)
w_eff = a_eff * (0.65 + 1.619 / V_eff ** 1.5 + 2.879 / V_eff ** 6) w_eff = a_eff * (0.65 + 1.619 / V_eff ** 1.5 + 2.879 / V_eff ** 6)
A_eff = interp1d(lambda_, w_eff, kind="linear")(units.m.inv(w0)) ** pipi A_eff = interp1d(lambda_, w_eff, kind="linear")(units.m.inv(w0)) ** 2 * pi
if n2 is None: if n2 is None:
n2 = 2.6e-20 n2 = 2.6e-20

View File

@@ -1,8 +1,13 @@
from typing import Any, Callable
import numpy as np import numpy as np
import scipy.special
from scipy.integrate import cumulative_trapezoid
from scgenerator import math
from ..logger import get_logger from ..logger import get_logger
from . import units from . import units
from .units import NA, c, kB, me, e from .units import NA, c, kB, me, e, hbar
def pressure_from_gradient(ratio, p0, p1): def pressure_from_gradient(ratio, p0, p1):
@@ -174,3 +179,57 @@ def non_linear_refractive_index(material_dico, pressure=None, temperature=None):
def adiabadicity(w: np.ndarray, I: float, field: np.ndarray) -> np.ndarray: def adiabadicity(w: np.ndarray, I: float, field: np.ndarray) -> np.ndarray:
return w * np.sqrt(2 * me * I) / (e * np.abs(field)) return w * np.sqrt(2 * me * I) / (e * np.abs(field))
def free_electron_density(
t: np.ndarray, field: np.ndarray, N0: float, rate_func: Callable[[np.ndarray], np.ndarray]
) -> np.ndarray:
return N0 * (1 - np.exp(-cumulative_trapezoid(rate_func(field), t, initial=0)))
def ionization_rate_ADK(
ionization_energy: float, atomic_number
) -> Callable[[np.ndarray], np.ndarray]:
Z = -(atomic_number - 1) * e
omega_p = ionization_energy / hbar
nstar = Z * np.sqrt(2.1787e-18 / ionization_energy)
omega_t = lambda field: e * np.abs(field) / np.sqrt(2 * me * ionization_energy)
Cnstar = 2 ** (2 * nstar) / (scipy.special.gamma(nstar + 1) ** 2)
omega_C = omega_p / 4 * math.abs2(Cnstar)
def rate(field: np.ndarray) -> np.ndarray:
opt4 = 4 * omega_t(field) / om
return omega_C * (4 * omega_p / ot) ** (2 * nstar - 1) * np.exp(-4 * omega_p / (3 * ot))
return rate
class Plasma:
def __init__(self, t: np.ndarray, ionization_energy: float, atomic_number: int):
self.t = t
self.Ip = ionization_energy
self.atomic_number = atomic_number
self.rate = ionization_rate_ADK(self.Ip, self.atomic_number)
def __call__(self, field: np.ndarray, N0: float) -> np.ndarray:
"""returns the number density of free electrons as function of time
Parameters
----------
field : np.ndarray
electric field in V/m
N0 : float
total number density of matter
Returns
-------
np.ndarray
number density of free electrons as function of time
"""
Ne = free_electron_density(self.t, field, N0, self.rate)
return cumulative_trapezoid(
np.gradient(Ne, self.t) * self.Ip / field, self.t, initial=0
) + e ** 2 / me * cumulative_trapezoid(
cumulative_trapezoid(Ne * field, self.t, initial=0), self.t, initial=0
)

View File

@@ -572,7 +572,7 @@ def peak_ind(values, mam=None):
) + 3 ) + 3
except IndexError: except IndexError:
right_ind = len(values) - 1 right_ind = len(values) - 1
return left_ind, right_ind return max(0, left_ind), min(len(values) - 1, right_ind)
def setup_splines(x_axis, values, mam=None): def setup_splines(x_axis, values, mam=None):
@@ -685,8 +685,7 @@ def find_lobe_limits(x_axis, values, debug="", already_sorted=True):
dd_roots, dd_roots,
fwhm_pos, fwhm_pos,
peak_pos, peak_pos,
folder_name, out_path,
file_name,
fig, fig,
ax, ax,
color, color,
@@ -716,7 +715,7 @@ def find_lobe_limits(x_axis, values, debug="", already_sorted=True):
c=color[5], c=color[5],
) )
ax.legend() ax.legend()
fig.savefig(os.path.join(folder_name, file_name), bbox_inches="tight") fig.savefig(out_path, bbox_inches="tight")
plt.close(fig) plt.close(fig)
else: else:
@@ -818,9 +817,7 @@ def _detailed_find_lobe_limits(
# if measurement of the peak is not straightforward, we plot the situation to see # if measurement of the peak is not straightforward, we plot the situation to see
# if the final measurement is good or not # if the final measurement is good or not
folder_name, file_name, fig, ax = plot_setup( out_path, fig, ax = plot_setup(out_path=f"measurement_errors_plots/it_{iterations}_{debug}")
file_name=f"it_{iterations}_{debug}", folder_name="measurements_errors_plots"
)
new_fwhm_pos = np.array([np.max(left_pos), np.min(right_pos)]) new_fwhm_pos = np.array([np.max(left_pos), np.min(right_pos)])
@@ -842,8 +839,7 @@ def _detailed_find_lobe_limits(
dd_roots, dd_roots,
fwhm_pos, fwhm_pos,
peak_pos, peak_pos,
folder_name, out_path,
file_name,
fig, fig,
ax, ax,
color, color,
@@ -946,7 +942,7 @@ def measure_field(t: np.ndarray, field: np.ndarray) -> Tuple[float, float, float
def remove_2nd_order_dispersion( def remove_2nd_order_dispersion(
spectrum: T, w_c: np.ndarray, beta2: float, max_z: float = -1.0 spectrum: T, w_c: np.ndarray, beta2: float, max_z: float = -100.0
) -> tuple[T, OptimizeResult]: ) -> tuple[T, OptimizeResult]:
"""attempts to remove 2nd order dispersion from a complex spectrum """attempts to remove 2nd order dispersion from a complex spectrum
@@ -964,11 +960,49 @@ def remove_2nd_order_dispersion(
np.ndarray, shape (n, ) np.ndarray, shape (n, )
spectrum with 2nd order dispersion removed spectrum with 2nd order dispersion removed
""" """
# makeshift_t = np.linspace(0, 1, len(w_c))
propagate = lambda z: spectrum * np.exp(-0.5j * beta2 * w_c ** 2 * z) propagate = lambda z: spectrum * np.exp(-0.5j * beta2 * w_c ** 2 * z)
def score(z): def score(z):
return 1 / np.max(abs2(np.fft.ifft(propagate(z)))) return -np.max(abs2(np.fft.ifft(propagate(z))))
opti = minimize_scalar(score, bracket=(max_z, 0)) opti = minimize_scalar(score, bracket=(max_z, 0))
return propagate(opti.x), opti return propagate(opti.x), opti
def remove_2nd_order_dispersion2(
spectrum: T, w_c: np.ndarray, max_gdd: float = 1000e-30
) -> tuple[T, OptimizeResult]:
"""attempts to remove 2nd order dispersion from a complex spectrum
Parameters
----------
spectrum : np.ndarray or Spectrum, shape (n, )
spectrum from which to remove 2nd order dispersion
w_c : np.ndarray, shape (n, )
corresponding centered angular frequencies (w-w0)
Returns
-------
np.ndarray, shape (n, )
spectrum with 2nd order dispersion removed
"""
propagate = lambda gdd: spectrum * np.exp(-0.5j * w_c ** 2 * 1e-30 * gdd)
integrate = lambda gdd: abs2(np.fft.ifft(propagate(gdd)))
def score(gdd):
return -np.sum(integrate(gdd) ** 6)
# def score(gdd):
# return -np.max(integrate(gdd))
# to_test = np.linspace(-max_gdd, max_gdd, 200)
# scores = [score(g) for g in to_test]
# fig, ax = plt.subplots()
# ax.plot(to_test, scores / np.min(scores))
# plt.show()
# plt.close(fig)
# ama = np.argmin(scores)
opti = minimize_scalar(score, bounds=(-max_gdd * 1e30, max_gdd * 1e30))
opti["x"] *= 1e-30
return propagate(opti.x * 1e30), opti

View File

@@ -1,5 +1,6 @@
import multiprocessing import multiprocessing
import os import os
import random
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
from typing import Dict, List, Tuple, Type from typing import Dict, List, Tuple, Type
@@ -704,7 +705,7 @@ def new_simulation(
if prev_sim_dir is not None: if prev_sim_dir is not None:
config_dict["prev_sim_dir"] = str(prev_sim_dir) config_dict["prev_sim_dir"] = str(prev_sim_dir)
task_id = np.random.randint(1e9, 1e12) task_id = random.randint(1e9, 1e12)
if prev_sim_dir is None: if prev_sim_dir is None:
param_seq = initialize.ParamSequence(config_dict) param_seq = initialize.ParamSequence(config_dict)
@@ -718,7 +719,7 @@ def new_simulation(
def resume_simulations(sim_dir: Path, method: Type[Simulations] = None) -> Simulations: def resume_simulations(sim_dir: Path, method: Type[Simulations] = None) -> Simulations:
task_id = np.random.randint(1e9, 1e12) task_id = random.randint(1e9, 1e12)
config = io.load_toml(sim_dir / "initial_config.toml") config = io.load_toml(sim_dir / "initial_config.toml")
io.set_data_folder(task_id, sim_dir) io.set_data_folder(task_id, sim_dir)
param_seq = initialize.RecoveryParamSequence(config, task_id) param_seq = initialize.RecoveryParamSequence(config, task_id)

View File

@@ -30,6 +30,7 @@ def plot_setup(
- an axis - an axis
""" """
out_path = defaults["name"] if out_path is None else out_path out_path = defaults["name"] if out_path is None else out_path
out_path = Path(out_path)
plot_name = out_path.name.replace(f".{file_type}", "") plot_name = out_path.name.replace(f".{file_type}", "")
out_dir = out_path.resolve().parent out_dir = out_path.resolve().parent