system in place, needs to integrate it

This commit is contained in:
Benoît Sierro
2021-08-26 13:54:17 +02:00
parent 1f0937d840
commit 4bcf5add60
19 changed files with 488 additions and 549 deletions

View File

@@ -48,7 +48,7 @@ note : internally, another structure with a flattened dictionary is used
## Fiber parameters ## Fiber parameters
If you already know the Taylor coefficients corresponding to the expansion of the beta2 profile, you can specify them and skip to "Other fiber parameters": If you already know the Taylor coefficients corresponding to the expansion of the beta2 profile, you can specify them and skip to "Other fiber parameters":
beta: list-like beta2_coefficients: list-like
list of Taylor coefficients for the beta_2 function list of Taylor coefficients for the beta_2 function
If you already have a dispersion curve, you can convert it to a npz file with the wavelength (key : 'wavelength') in m and the D parameter (key : 'dispersion') in s/m/m. You the refer to this file as If you already have a dispersion curve, you can convert it to a npz file with the wavelength (key : 'wavelength') in m and the D parameter (key : 'dispersion') in s/m/m. You the refer to this file as
@@ -239,15 +239,8 @@ parallel: bool
repeat: int repeat: int
how many simulations to run per parameter set. default : 1 how many simulations to run per parameter set. default : 1
lower_wavelength_interp_limit: float interpolation_range : tuple[float, float]
dispersion coefficients are computed over a certain wavelength range. This parameter range over which dispersion is computed and interpolated in m. ex: (500e-9, 2000e-9)
sets the lowest end of this range. If the set value is lower than the lower end of the
wavelength window, it is raised up to that point. default : 0
upper_wavelength_interp_limit: float
dispersion coefficients are computed over a certain wavelength range. This parameter
sets the lowest end of this range. If the set value is higher than the higher end of the
wavelength window, it is lowered down to that point. default : 1900e-9
interpolation_degree: int interpolation_degree: int
max degree of the Taylor polynomial fitting the dispersion data max degree of the Taylor polynomial fitting the dispersion data

View File

@@ -1,4 +1,4 @@
__version__ = "0.1.1" __version__ = "0.1.1rules"
from typing import Any from typing import Any

View File

@@ -24,9 +24,8 @@ default_parameters = dict(
parallel=True, parallel=True,
repeat=1, repeat=1,
tolerated_error=1e-11, tolerated_error=1e-11,
lower_wavelength_interp_limit=100e-9,
upper_wavelength_interp_limit=2000e-9,
interpolation_degree=8, interpolation_degree=8,
interpolation_range=(200e-9, 3000e-9),
ideal_gas=False, ideal_gas=False,
recovery_last_stored=0, recovery_last_stored=0,
) )

View File

@@ -32,123 +32,6 @@ class Params(BareParams):
def compute(self): def compute(self):
logger = get_logger(__name__) logger = get_logger(__name__)
self.__build_sim_grid()
did_set_custom_pulse = self.__compute_custom_pulse()
self.__compute_fiber()
if not did_set_custom_pulse:
logger.info(f"using generic input pulse of {self.shape.title()} shape")
self.__compute_generic_pulse()
if self.quantum_noise and self.prev_sim_dir is None:
self.field_0 = self.field_0 + pulse.shot_noise(
self.w_c, self.w0, self.time_window, self.dt
)
logger.info("added some quantum noise")
if self.step_size is not None:
self.error_ok = self.step_size
self.adapt_step_size = False
else:
self.error_ok = self.tolerated_error
self.adapt_step_size = True
self.spec_0 = np.fft.fft(self.field_0)
def __build_sim_grid(self):
build_sim_grid_in_place(self)
def __compute_generic_pulse(self):
(
self.width,
self.t0,
self.peak_power,
self.energy,
self.soliton_num,
) = pulse.conform_pulse_params(
self.shape,
self.width,
self.t0,
self.peak_power,
self.energy,
self.soliton_num,
self.gamma,
self.beta[0],
)
logger = get_logger(__name__)
logger.info(f"computed initial N = {self.soliton_num:.3g}")
self.L_D = self.t0 ** 2 / abs(self.beta[0])
self.L_NL = 1 / (self.gamma * self.peak_power) if self.gamma else np.inf
self.L_sol = pi / 2 * self.L_D
# Technical noise
if self.intensity_noise is not None and self.intensity_noise > 0:
delta_int, delta_T0 = pulse.technical_noise(self.intensity_noise)
self.peak_power *= delta_int
self.t0 *= delta_T0
self.width *= delta_T0
self.field_0 = pulse.initial_field(self.t, self.shape, self.t0, self.peak_power)
def __compute_fiber(self):
logger = get_logger(__name__)
self.interp_range = (
max(self.lower_wavelength_interp_limit, self.l[self.l > 0].min()),
min(self.upper_wavelength_interp_limit, self.l[self.l > 0].max()),
)
temp_gamma = None
if self.A_eff_file is not None:
self.A_eff_arr = fiber.compute_custom_A_eff(self)
elif self.A_eff is not None:
self.A_eff_arr = np.ones(self.t_num) * self.A_eff
elif self.effective_mode_diameter is not None:
self.A_eff_arr = np.ones(self.t_num) * (self.effective_mode_diameter / 2) ** 2 * pi
else:
self.A_eff_arr = np.ones(self.t_num) * self.n2 * self.w0 / (299792458.0 * self.gamma)
self.A_eff = self.A_eff_arr[0]
if self.beta is not None:
self.beta = np.array(self.beta)
self.dynamic_dispersion = False
else:
self.dynamic_dispersion = fiber.is_dynamic_dispersion(self.pressure)
self.beta, temp_gamma, self.interp_range = fiber.compute_dispersion(self)
if self.dynamic_dispersion:
self.gamma_func = temp_gamma
self.beta_func = self.beta
self.beta = self.beta_func(0)
temp_gamma = temp_gamma(0)
if self.gamma is None:
self.gamma_arr = temp_gamma
self.gamma = temp_gamma[0]
logger.info(f"using computed \u0263 = {self.gamma:.2e} W/m\u00B2")
else:
self.gamma_arr = np.ones(self.t_num) * self.gamma
# Raman response
if "raman" in self.behaviors:
self.hr_w = fiber.delayed_raman_w(self.t, self.dt, self.raman_type)
self.alpha = fiber.compute_loss(self)
def __compute_custom_pulse(self):
logger = get_logger(__name__)
if self.mean_power is not None:
self.energy = self.mean_power / self.repetition_rate
(
did_set_custom_pulse,
self.width,
self.peak_power,
self.energy,
self.field_0,
) = pulse.setup_custom_field(self)
return did_set_custom_pulse
@dataclass @dataclass
class Config(BareConfig): class Config(BareConfig):
@@ -169,7 +52,7 @@ class Config(BareConfig):
def fiber_consistency(self): def fiber_consistency(self):
if self.contains("dispersion_file") or self.contains("beta"): if self.contains("dispersion_file") or self.contains("beta2_coefficients"):
if not ( if not (
self.contains("A_eff") self.contains("A_eff")
or self.contains("A_eff_file") or self.contains("A_eff_file")
@@ -241,8 +124,7 @@ class Config(BareConfig):
"tolerated_error", "tolerated_error",
"parallel", "parallel",
"repeat", "repeat",
"lower_wavelength_interp_limit", "interpolation_range",
"upper_wavelength_interp_limit",
"interpolation_degree", "interpolation_degree",
"ideal_gas", "ideal_gas",
"recovery_last_stored", "recovery_last_stored",

View File

@@ -23,14 +23,14 @@ pipi = 2 * pi
T = TypeVar("T") T = TypeVar("T")
def lambda_for_dispersion(left: float, right: float) -> np.ndarray: def lambda_for_dispersion(interpolation_range: tuple[float, float]) -> np.ndarray:
"""Returns a wl vector for dispersion calculation """Returns a wl vector for dispersion calculation
Returns Returns
------- -------
array of wl values array of wl values
""" """
return np.arange(left - 2e-9, right + 3e-9, 1e-9) return np.arange(interpolation_range[0] - 2e-9, interpolation_range[1] + 3e-9, 1e-9)
def is_dynamic_dispersion(pressure=None): def is_dynamic_dispersion(pressure=None):
@@ -73,7 +73,7 @@ def HCARF_gap(core_radius: float, capillary_num: int, capillary_outer_d: float):
) - capillary_outer_d ) - capillary_outer_d
def dispersion_parameter(n_eff: np.ndarray, lambda_: np.ndarray): def gvd_from_n_eff(n_eff: np.ndarray, wl_for_disp: np.ndarray):
"""computes the dispersion parameter D from an effective index of refraction n_eff """computes the dispersion parameter D from an effective index of refraction n_eff
Since computing gradients/derivatives of discrete arrays is not well defined on the boundary, it is Since computing gradients/derivatives of discrete arrays is not well defined on the boundary, it is
advised to chop off the two values on either end of the returned array advised to chop off the two values on either end of the returned array
@@ -82,26 +82,26 @@ def dispersion_parameter(n_eff: np.ndarray, lambda_: np.ndarray):
---------- ----------
n_eff : 1D array n_eff : 1D array
a wl-dependent index of refraction a wl-dependent index of refraction
lambda_ : 1D array wl_for_disp : 1D array
the wavelength array (len must match n_eff) the wavelength array (len must match n_eff)
Returns Returns
------- -------
D : 1D array D : 1D array
wl-dependent dispersion parameter as function of lambda_ wl-dependent dispersion parameter as function of wl_for_disp
""" """
return -lambda_ / c * (np.gradient(np.gradient(n_eff, lambda_), lambda_)) return -wl_for_disp / c * (np.gradient(np.gradient(n_eff, wl_for_disp), wl_for_disp))
def beta2_to_D(beta2, λ): def beta2_to_D(beta2, wl_for_disp):
"""returns the D parameter corresponding to beta2(λ)""" """returns the D parameter corresponding to beta2(wl_for_disp)"""
return -(pipi * c) / (λ ** 2) * beta2 return -(pipi * c) / (wl_for_disp ** 2) * beta2
def D_to_beta2(D, λ): def D_to_beta2(D, wl_for_disp):
"""returns the beta2 parameters corresponding to D(λ)""" """returns the beta2 parameters corresponding to D(wl_for_disp)"""
return -(λ ** 2) / (pipi * c) * D return -(wl_for_disp ** 2) / (pipi * c) * D
def A_to_C(A: np.ndarray, A_eff_arr: np.ndarray) -> np.ndarray: def A_to_C(A: np.ndarray, A_eff_arr: np.ndarray) -> np.ndarray:
@@ -112,12 +112,12 @@ def C_to_A(C: np.ndarray, A_eff_arr: np.ndarray) -> np.ndarray:
return (A_eff_arr / A_eff_arr[0]) ** (1 / 4) * C return (A_eff_arr / A_eff_arr[0]) ** (1 / 4) * C
def plasma_dispersion(lambda_, number_density, simple=False): def plasma_dispersion(wl_for_disp, number_density, simple=False):
"""computes dispersion (beta2) for constant plasma """computes dispersion (beta2) for constant plasma
Parameters Parameters
---------- ----------
lambda_ : array-like wl_for_disp : array-like
wavelengths over which to calculate the dispersion wavelengths over which to calculate the dispersion
number_density : number of ionized atoms /m^3 number_density : number of ionized atoms /m^3
@@ -128,7 +128,7 @@ def plasma_dispersion(lambda_, number_density, simple=False):
""" """
e2_me_e0 = 3182.60735 # e^2 /(m_e * epsilon_0) e2_me_e0 = 3182.60735 # e^2 /(m_e * epsilon_0)
w = units.m(lambda_) w = units.m(wl_for_disp)
if simple: if simple:
w_pl = number_density * e2_me_e0 w_pl = number_density * e2_me_e0
return -(w_pl ** 2) / (c * w ** 2) return -(w_pl ** 2) / (c * w ** 2)
@@ -138,15 +138,15 @@ def plasma_dispersion(lambda_, number_density, simple=False):
return beta2 return beta2
def n_eff_marcatili(lambda_, n_gas_2, core_radius, he_mode=(1, 1)): def n_eff_marcatili(wl_for_disp, n_gas_2, core_radius, he_mode=(1, 1)):
"""computes the effective refractive index according to the Marcatili model of a capillary """computes the effective refractive index according to the Marcatili model of a capillary
Parameters Parameters
---------- ----------
lambda_ : ndarray, shape (n, ) wl_for_disp : ndarray, shape (n, )
wavelengths array (m) wavelengths array (m)
n_gas_2 : ndarray, shape (n, ) n_gas_2 : ndarray, shape (n, )
square of the refractive index of the gas as function of lambda_ square of the refractive index of the gas as function of wl_for_disp
core_radius : float core_radius : float
inner radius of the capillary (m) inner radius of the capillary (m)
he_mode : tuple, shape (2, ), optional he_mode : tuple, shape (2, ), optional
@@ -162,18 +162,18 @@ def n_eff_marcatili(lambda_, n_gas_2, core_radius, he_mode=(1, 1)):
""" """
u = u_nm(*he_mode) u = u_nm(*he_mode)
return np.sqrt(n_gas_2 - (lambda_ * u / (pipi * core_radius)) ** 2) return np.sqrt(n_gas_2 - (wl_for_disp * u / (pipi * core_radius)) ** 2)
def n_eff_marcatili_adjusted(lambda_, n_gas_2, core_radius, he_mode=(1, 1), fit_parameters=()): def n_eff_marcatili_adjusted(wl_for_disp, n_gas_2, core_radius, he_mode=(1, 1), fit_parameters=()):
"""computes the effective refractive index according to the Marcatili model of a capillary but adjusted at longer wavelengths """computes the effective refractive index according to the Marcatili model of a capillary but adjusted at longer wavelengths
Parameters Parameters
---------- ----------
lambda_ : ndarray, shape (n, ) wl_for_disp : ndarray, shape (n, )
wavelengths array (m) wavelengths array (m)
n_gas_2 : ndarray, shape (n, ) n_gas_2 : ndarray, shape (n, )
refractive index of the gas as function of lambda_ refractive index of the gas as function of wl_for_disp
core_radius : float core_radius : float
inner radius of the capillary (m) inner radius of the capillary (m)
he_mode : tuple, shape (2, ), optional he_mode : tuple, shape (2, ), optional
@@ -191,45 +191,42 @@ def n_eff_marcatili_adjusted(lambda_, n_gas_2, core_radius, he_mode=(1, 1), fit_
""" """
u = u_nm(*he_mode) u = u_nm(*he_mode)
corrected_radius = effective_core_radius(lambda_, core_radius, *fit_parameters) corrected_radius = effective_core_radius(wl_for_disp, core_radius, *fit_parameters)
return np.sqrt(n_gas_2 - (lambda_ * u / (pipi * corrected_radius)) ** 2) return np.sqrt(n_gas_2 - (wl_for_disp * u / (pipi * corrected_radius)) ** 2)
@np_cache @np_cache
def n_eff_hasan( def n_eff_hasan(
lambda_: np.ndarray, wl_for_disp: np.ndarray,
n_gas_2: np.ndarray, n_gas_2: np.ndarray,
core_radius: float, core_radius: float,
capillary_num: int, capillary_num: int,
capillary_nested: int,
capillary_thickness: float, capillary_thickness: float,
capillary_outer_d: float = None, capillary_spacing: float,
capillary_spacing: float = None, capillary_resonance_strengths: list[float],
capillary_resonance_strengths: list[float] = [],
capillary_nested: int = 0,
) -> np.ndarray: ) -> np.ndarray:
"""computes the effective refractive index of the fundamental mode according to the Hasan model for a anti-resonance fiber """computes the effective refractive index of the fundamental mode according to the Hasan model for a anti-resonance fiber
Parameters Parameters
---------- ----------
lambda_ wl_for_disp
wavelenghs array (m) wavelenghs array (m)
n_gas_2 : ndarray, shape (n, ) n_gas_2 : ndarray, shape (n, )
squared refractive index of the gas as a function of lambda_ squared refractive index of the gas as a function of wl_for_disp
core_radius : float core_radius : float
radius of the core (m) (from cented to edge of a capillary) radius of the core (m) (from cented to edge of a capillary)
capillary_num : int capillary_num : int
number of capillaries number of capillaries
capillary_thickness : float
thickness of the capillaries (m)
capillary_outer_d : float, optional if capillary_spacing is given
diameter of the capillaries including the wall thickness(m). The core together with the microstructure has a diameter of 2R + 2d
capillary_spacing : float, optional if capillary_outer_d is given
spacing between capillaries (m)
capillary_resonance_strengths : list or tuple, optional
strengths of the resonance lines. default : []
capillary_nested : int, optional capillary_nested : int, optional
number of levels of nested capillaries. default : 0 number of levels of nested capillaries. default : 0
capillary_thickness : float
thickness of the capillaries (m)
capillary_spacing : float
spacing between capillaries (m)
capillary_resonance_strengths : list or tuple
strengths of the resonance lines. may be empty
Returns Returns
------- -------
@@ -241,12 +238,7 @@ def n_eff_hasan(
Hasan, Md Imran, Nail Akhmediev, and Wonkeun Chang. "Empirical formulae for dispersion and effective mode area in hollow-core antiresonant fibers." Journal of Lightwave Technology 36.18 (2018): 4060-4065. Hasan, Md Imran, Nail Akhmediev, and Wonkeun Chang. "Empirical formulae for dispersion and effective mode area in hollow-core antiresonant fibers." Journal of Lightwave Technology 36.18 (2018): 4060-4065.
""" """
u = u_nm(1, 1) u = u_nm(1, 1)
if capillary_spacing is None:
capillary_spacing = HCARF_gap(core_radius, capillary_num, capillary_outer_d)
elif capillary_outer_d is None:
capillary_outer_d = (2 * core_radius * np.sin(pi / capillary_num) - capillary_spacing) / (
1 - np.sin(pi / capillary_num)
)
Rg = core_radius / capillary_spacing Rg = core_radius / capillary_spacing
f1 = 1.095 * np.exp(0.097041 / Rg) f1 = 1.095 * np.exp(0.097041 / Rg)
@@ -254,18 +246,18 @@ def n_eff_hasan(
if capillary_nested > 0: if capillary_nested > 0:
f2 += 0.0045 * np.exp(-4.1589 / (capillary_nested * Rg)) f2 += 0.0045 * np.exp(-4.1589 / (capillary_nested * Rg))
R_eff = f1 * core_radius * (1 - f2 * lambda_ ** 2 / (core_radius * capillary_thickness)) R_eff = f1 * core_radius * (1 - f2 * wl_for_disp ** 2 / (core_radius * capillary_thickness))
n_eff_2 = n_gas_2 - (u * lambda_ / (pipi * R_eff)) ** 2 n_eff_2 = n_gas_2 - (u * wl_for_disp / (pipi * R_eff)) ** 2
chi_sil = mat.sellmeier(lambda_, io.load_material_dico("silica")) chi_sil = mat.sellmeier(wl_for_disp, io.load_material_dico("silica"))
with np.errstate(divide="ignore", invalid="ignore"): with np.errstate(divide="ignore", invalid="ignore"):
for m, strength in enumerate(capillary_resonance_strengths): for m, strength in enumerate(capillary_resonance_strengths):
n_eff_2 += ( n_eff_2 += (
strength strength
* lambda_ ** 2 * wl_for_disp ** 2
/ (lambda_ ** 2 - chi_sil * (2 * capillary_thickness / (m + 1)) ** 2) / (wl_for_disp ** 2 - chi_sil * (2 * capillary_thickness / (m + 1)) ** 2)
) )
return np.sqrt(n_eff_2) return np.sqrt(n_eff_2)
@@ -291,7 +283,44 @@ def A_eff_hasan(core_radius, capillary_num, capillary_spacing):
return M_f * core_radius ** 2 * np.exp((capillary_spacing / 22e-6) ** 2.5) return M_f * core_radius ** 2 * np.exp((capillary_spacing / 22e-6) ** 2.5)
def A_eff_marcuse(wl: T, core_radius: float, numerical_aperture: float) -> T: def V_eff_marcuse(l: T, core_radius: float, numerical_aperture: float) -> T:
return 2 * pi * core_radius * numerical_aperture / l
def V_parameter_koshiba(l: np.ndarray, pitch: float, pitch_ratio: float) -> float:
"""returns the V parameter according to Koshiba2004
Parameters
----------
l : np.ndarray, shape (n,)
wavelength
pitch : float
distance between air holes in m
pitch_ratio : float
ratio diameter of holes / distance
w0 : float
pump angular frequency
Returns
-------
float
effective mode field area
"""
ratio_l = l / pitch
n_co = 1.45
a_eff = pitch / np.sqrt(3)
pi2a = pipi * a_eff
A, B = saitoh_paramters(pitch_ratio)
V = A[0] + A[1] / (1 + A[2] * np.exp(A[3] * ratio_l))
n_FSM2 = 1.45 ** 2 - (l * V / (pi2a)) ** 2
V_eff = pi2a / l * np.sqrt(n_co ** 2 - n_FSM2)
return V_eff
def A_eff_from_V(core_radius: float, V_eff: T) -> T:
"""According to Marcuse1978 """According to Marcuse1978
Parameters Parameters
@@ -308,8 +337,7 @@ def A_eff_marcuse(wl: T, core_radius: float, numerical_aperture: float) -> T:
T T
A_eff as function of wl A_eff as function of wl
""" """
V = 2 * pi * core_radius * numerical_aperture / wl return core_radius * (0.65 + 1.619 / V_eff ** 1.5 + 2.879 / V_eff ** 6)
w_eff = core_radius * (0.65 + 1.619 / V ** 1.5 + 2.879 / V ** 6)
def HCPCF_find_with_given_ZDW( def HCPCF_find_with_given_ZDW(
@@ -449,7 +477,7 @@ def HCPF_ZDW(
return l[zdw_ind] return l[zdw_ind]
def beta2(w: np.ndarray, n_eff: np.ndarray) -> np.ndarray: def beta2(w_for_disp: np.ndarray, n_eff: np.ndarray) -> np.ndarray:
"""computes the dispersion parameter beta2 according to the effective refractive index of the fiber and the frequency range """computes the dispersion parameter beta2 according to the effective refractive index of the fiber and the frequency range
Parameters Parameters
@@ -463,11 +491,11 @@ def beta2(w: np.ndarray, n_eff: np.ndarray) -> np.ndarray:
------- -------
beta2 : ndarray, shape (n, ) beta2 : ndarray, shape (n, )
""" """
return np.gradient(np.gradient(n_eff * w / c, w), w) return np.gradient(np.gradient(n_eff * w_for_disp / c, w_for_disp), w_for_disp)
def HCPCF_dispersion( def HCPCF_dispersion(
lambda_, wl_for_disp,
material_dico=None, material_dico=None,
model="marcatili", model="marcatili",
model_params={}, model_params={},
@@ -479,7 +507,7 @@ def HCPCF_dispersion(
Parameters Parameters
---------- ----------
lambda_ : ndarray, shape (n, ) wl_for_disp : ndarray, shape (n, )
wavelengths over which to calculate the dispersion wavelengths over which to calculate the dispersion
material_dico : dict material_dico : dict
material dictionary respecting standard format explained in FIXME material dictionary respecting standard format explained in FIXME
@@ -487,7 +515,7 @@ def HCPCF_dispersion(
which model of effective refractive index to use which model of effective refractive index to use
model_params : tuple model_params : tuple
to be cast to the function in charge of computing the effective index of the fiber. Every n_eff_* function has a signature to be cast to the function in charge of computing the effective index of the fiber. Every n_eff_* function has a signature
n_eff_(lambda_, n_gas_2, radius, *args) and model_params corresponds to args n_eff_(wl_for_disp, n_gas_2, radius, *args) and model_params corresponds to args
temperature : float temperature : float
Temperature of the material Temperature of the material
pressure : float pressure : float
@@ -499,29 +527,29 @@ def HCPCF_dispersion(
beta2 as function of wavelength beta2 as function of wavelength
""" """
w = units.m(lambda_) w = units.m(wl_for_disp)
if material_dico is None: if material_dico is None:
n_gas_2 = np.ones_like(lambda_) n_gas_2 = np.ones_like(wl_for_disp)
else: else:
if ideal: if ideal:
n_gas_2 = mat.sellmeier(lambda_, material_dico, pressure, temperature) + 1 n_gas_2 = mat.sellmeier(wl_for_disp, material_dico, pressure, temperature) + 1
else: else:
N_1 = mat.number_density_van_der_waals( N_1 = mat.number_density_van_der_waals(
pressure=pressure, temperature=temperature, material_dico=material_dico pressure=pressure, temperature=temperature, material_dico=material_dico
) )
N_0 = mat.number_density_van_der_waals(material_dico=material_dico) N_0 = mat.number_density_van_der_waals(material_dico=material_dico)
n_gas_2 = mat.sellmeier(lambda_, material_dico) * N_1 / N_0 + 1 n_gas_2 = mat.sellmeier(wl_for_disp, material_dico) * N_1 / N_0 + 1
n_eff_func = dict( n_eff_func = dict(
marcatili=n_eff_marcatili, marcatili_adjusted=n_eff_marcatili_adjusted, hasan=n_eff_hasan marcatili=n_eff_marcatili, marcatili_adjusted=n_eff_marcatili_adjusted, hasan=n_eff_hasan
)[model] )[model]
n_eff = n_eff_func(lambda_, n_gas_2, **model_params) n_eff = n_eff_func(wl_for_disp, n_gas_2, **model_params)
return beta2(w, n_eff) return beta2(w, n_eff)
def dynamic_HCPCF_dispersion( def dynamic_HCPCF_dispersion(
lambda_: np.ndarray, wl_for_disp: np.ndarray,
pressure_values: List[float], pressure_values: List[float],
core_radius: float, core_radius: float,
fiber_model: str, fiber_model: str,
@@ -537,7 +565,7 @@ def dynamic_HCPCF_dispersion(
Parameters Parameters
---------- ----------
lambda_ : wavelength array wl_for_disp : wavelength array
params : dict params : dict
flattened parameter dictionary flattened parameter dictionary
material_dico : dict material_dico : dict
@@ -558,7 +586,7 @@ def dynamic_HCPCF_dispersion(
# defining function instead of storing every possilble value # defining function instead of storing every possilble value
pressure = lambda r: mat.pressure_from_gradient(r, *pressure_values) pressure = lambda r: mat.pressure_from_gradient(r, *pressure_values)
beta2 = lambda r: HCPCF_dispersion( beta2 = lambda r: HCPCF_dispersion(
lambda_, wl_for_disp,
core_radius, core_radius,
material_dico, material_dico,
fiber_model, fiber_model,
@@ -575,7 +603,7 @@ def dynamic_HCPCF_dispersion(
gamma_interp = interp1d(ratio_range, gamma_grid) gamma_interp = interp1d(ratio_range, gamma_grid)
beta2_grid = np.array( beta2_grid = np.array(
[dispersion_coefficients(lambda_, beta2(r), w0, interp_range, deg) for r in ratio_range] [dispersion_coefficients(wl_for_disp, beta2(r), w0, interp_range, deg) for r in ratio_range]
) )
beta2_interp = [ beta2_interp = [
interp1d(ratio_range, beta2_grid[:, i], assume_sorted=True) for i in range(deg + 1) interp1d(ratio_range, beta2_grid[:, i], assume_sorted=True) for i in range(deg + 1)
@@ -598,28 +626,28 @@ def gamma_parameter(n2: float, w0: float, A_eff: T) -> T:
return n2 * w0 / (A_eff_term * c) return n2 * w0 / (A_eff_term * c)
def constant_A_eff_arr(l: np.ndarray, A_eff: float) -> np.ndarray:
return np.ones_like(l) * A_eff
@np_cache @np_cache
def PCF_dispersion(lambda_, pitch, ratio_d, w0=None, n2=None, A_eff=None): def n_eff_pcf(wl_for_disp: np.ndarray, pitch: float, pitch_ratio: float) -> np.ndarray:
""" """
semi-analytical computation of the dispersion profile of a triangular Index-guiding PCF semi-analytical computation of the dispersion profile of a triangular Index-guiding PCF
Parameters Parameters
---------- ----------
lambda_ : 1D array-like wl_for_disp : np.ndarray, shape (n,)
wavelengths over which to calculate the dispersion wavelengths over which to calculate the dispersion
pitch : float pitch : float
distance between air holes in m distance between air holes in m
ratio_d : float pitch_ratio : float
ratio diameter of hole / pitch ratio diameter of hole / pitch
w0 : float, optional
pump angular frequency. If given, the gamma value is also returned in adition to the GVD. default : None
Returns Returns
------- -------
beta2 : 1D array n_eff : np.ndarray, shape (n,)
Dispersion parameter as function of wavelength effective index of refraction
gamma : float
non-linear coefficient
Reference Reference
--------- ---------
@@ -627,15 +655,38 @@ def PCF_dispersion(lambda_, pitch, ratio_d, w0=None, n2=None, A_eff=None):
""" """
# Check validity # Check validity
if ratio_d < 0.2 or ratio_d > 0.8: if pitch_ratio < 0.2 or pitch_ratio > 0.8:
print("WARNING : Fitted formula valid only for pitch ratio between 0.2 and 0.8") print("WARNING : Fitted formula valid only for pitch ratio between 0.2 and 0.8")
n_co = 1.45 n_co = 1.45
a_eff = pitch / np.sqrt(3) a_eff = pitch / np.sqrt(3)
pi2a = pipi * a_eff pi2a = pipi * a_eff
ratio_l = lambda_ / pitch ratio_l = wl_for_disp / pitch
A, B = saitoh_paramters(pitch_ratio)
V = A[0] + A[1] / (1 + A[2] * np.exp(A[3] * ratio_l))
W = B[0] + B[1] / (1 + B[2] * np.exp(B[3] * ratio_l))
n_FSM2 = 1.45 ** 2 - (wl_for_disp * V / (pi2a)) ** 2
n_eff2 = (wl_for_disp * W / (pi2a)) ** 2 + n_FSM2
n_eff = np.sqrt(n_eff2)
material_dico = io.load_material_dico("silica")
chi_mat = mat.sellmeier(wl_for_disp, material_dico)
return n_eff + np.sqrt(chi_mat + 1)
def A_eff_from_diam(effective_mode_diameter: float) -> float:
return pi * (effective_mode_diameter / 2) ** 2
def A_eff_from_gamma(gamma: float, n2: float, w0: float):
return n2 * w0 / (c * gamma)
def saitoh_paramters(pitch_ratio: float) -> tuple[float, float]:
# Table 1 and 2 in Saitoh2005 # Table 1 and 2 in Saitoh2005
ai0 = np.array([0.54808, 0.71041, 0.16904, -1.52736]) ai0 = np.array([0.54808, 0.71041, 0.16904, -1.52736])
ai1 = np.array([5.00401, 9.73491, 1.85765, 1.06745]) ai1 = np.array([5.00401, 9.73491, 1.85765, 1.06745])
@@ -652,185 +703,96 @@ def PCF_dispersion(lambda_, pitch, ratio_d, w0=None, n2=None, A_eff=None):
di2 = np.array([9, 6.58, 10, 0.41]) di2 = np.array([9, 6.58, 10, 0.41])
di3 = np.array([10, 24.8, 15, 6]) di3 = np.array([10, 24.8, 15, 6])
A = ai0 + ai1 * ratio_d ** bi1 + ai2 * ratio_d ** bi2 + ai3 * ratio_d ** bi3 A = ai0 + ai1 * pitch_ratio ** bi1 + ai2 * pitch_ratio ** bi2 + ai3 * pitch_ratio ** bi3
B = ci0 + ci1 * ratio_d ** di1 + ci2 * ratio_d ** di2 + ci3 * ratio_d ** di3 B = ci0 + ci1 * pitch_ratio ** di1 + ci2 * pitch_ratio ** di2 + ci3 * pitch_ratio ** di3
return A, B
V = A[0] + A[1] / (1 + A[2] * np.exp(A[3] * ratio_l))
W = B[0] + B[1] / (1 + B[2] * np.exp(B[3] * ratio_l))
n_FSM2 = 1.45 ** 2 - (lambda_ * V / (pi2a)) ** 2
n_eff2 = (lambda_ * W / (pi2a)) ** 2 + n_FSM2
n_eff = np.sqrt(n_eff2)
D_wave_guide = dispersion_parameter(n_eff, lambda_)
material_dico = io.load_material_dico("silica")
chi_mat = mat.sellmeier(lambda_, material_dico)
D_mat = dispersion_parameter(np.sqrt(chi_mat + 1), lambda_)
# material index of refraction (Sellmeier formula)
D = D_wave_guide + D_mat
beta2 = D_to_beta2(D, lambda_)
if w0 is None:
return beta2
else:
# effective mode field area (koshiba2004)
if A_eff is None:
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)
A_eff = interp1d(lambda_, w_eff, kind="linear")(units.m.inv(w0)) ** 2 * pi
if n2 is None:
n2 = 2.6e-20
gamma = gamma_parameter(n2, w0, A_eff)
return beta2, gamma
def compute_custom_A_eff(params: BareParams) -> np.ndarray: def load_custom_A_eff(A_eff_file: str, l: np.ndarray) -> np.ndarray:
data = np.load(params.A_eff_file) """loads custom effective area file
A_eff = data["A_eff"]
wl = data["wavelength"]
return interp1d(wl, A_eff, fill_value=1, bounds_error=False)(params.l)
def compute_loss(params: BareParams) -> Optional[np.ndarray]:
if params.loss_file is not None:
loss_data = np.load(params.loss_file)
wl = loss_data["wavelength"]
loss = loss_data["loss"]
return interp1d(wl, loss, fill_value=0, bounds_error=False)(params.l)
elif params.loss == "capillary":
mask = params.l < params.upper_wavelength_interp_limit
alpha = capillary_loss(params.l[mask], params.he_mode, params.core_radius)
out = np.zeros_like(params.l)
out[mask] = alpha
return out
return None
def compute_dispersion(params: BareParams) -> tuple[np.ndarray, np.ndarray, tuple[float, float]]:
"""dispatch function depending on what type of fiber is used
Parameters Parameters
---------- ----------
fiber_model : str {"PCF", "HCPCF"} A_eff_file : str
describes the type of fiber relative or absolute path to the file
- PCF : triangular Index-guiding photonic crystal fiber l : np.ndarray, shape (n,)
- HCPCF : hollow core fiber (filled with gas, or not) wavelength array of the simulation
params : dict
parameter dictionary as in `parameters.toml`
Returns Returns
------- -------
beta2_coef : 1D array of size deg np.ndarray, shape (n,)
beta coefficients to be used in disp_op wl-dependent effective mode field area
gamma : float
nonlinear parameter
""" """
data = np.load(A_eff_file)
A_eff = data["A_eff"]
wl = data["wavelength"]
return interp1d(wl, A_eff, fill_value=1, bounds_error=False)(l)
if params.dispersion_file is not None:
disp_file = np.load(params.dispersion_file) def load_custom_dispersion(dispersion_file: str) -> tuple[np.ndarray, np.ndarray]:
lambda_ = disp_file["wavelength"] disp_file = np.load(dispersion_file)
interp_range = (np.min(lambda_), np.max(lambda_)) wl_for_disp = disp_file["wavelength"]
interp_range = (np.min(wl_for_disp), np.max(wl_for_disp))
D = disp_file["dispersion"] D = disp_file["dispersion"]
beta2 = D_to_beta2(D, lambda_) beta2 = D_to_beta2(D, wl_for_disp)
gamma = None return wl_for_disp, beta2, interp_range
else:
interp_range = params.interp_range
lambda_ = lambda_for_dispersion(*interp_range)
beta2 = np.zeros_like(lambda_)
if params.model == "pcf":
beta2, gamma = PCF_dispersion(
lambda_,
params.pitch,
params.pitch_ratio,
w0=params.w0,
n2=params.n2,
A_eff=params.A_eff,
)
else: def load_custom_loss(l: np.ndarray, loss_file: str) -> np.ndarray:
material_dico = io.load_material_dico(params.gas_name) """loads a npz loss file that contains a wavelength and a loss entry
if params.dynamic_dispersion:
return dynamic_HCPCF_dispersion(
lambda_,
params.pressure,
params.core_radius,
params.model,
{k: getattr(params, k) for k in hc_model_specific_parameters[params.model]},
params.temperature,
params.ideal_gas,
params.w0,
params.interp_range,
material_dico,
params.interpolation_degree,
)
else:
beta2 = HCPCF_dispersion(
lambda_,
material_dico,
params.model,
{k: getattr(params, k) for k in hc_model_specific_parameters[params.model]},
params.pressure,
params.temperature,
params.ideal_gas,
)
if material_dico is not None: Parameters
----------
l : np.ndarray, shape (n,)
wavelength array of the simulation
loss_file : str
relative or absolute path to the loss file
A_eff = 1.5 * params.core_radius ** 2 if params.A_eff is None else params.A_eff Returns
if params.n2 is None: -------
n2 = mat.non_linear_refractive_index( np.ndarray, shape (n,)
material_dico, params.pressure, params.temperature loss in 1/m units
) """
else: loss_data = np.load(loss_file)
n2 = params.n2 wl = loss_data["wavelength"]
gamma = gamma_parameter(n2, params.w0, A_eff) loss = loss_data["loss"]
else: return interp1d(wl, loss, fill_value=0, bounds_error=False)(l)
gamma = None
# add plasma if wanted
if params.plasma_density > 0:
beta2 += plasma_dispersion(lambda_, params.plasma_density)
beta2_coef = dispersion_coefficients( def compute_capillary_loss(
lambda_, beta2, params.w0, interp_range, params.interpolation_degree l: np.ndarray,
) core_radius: float,
interpolation_range: tuple[float, float],
if gamma is None: he_mode: tuple[int, int],
if params.A_eff_arr is not None: ) -> np.ndarray:
gamma_arr = gamma_parameter(params.n2, params.w0, params.A_eff_arr) mask = l < interpolation_range[1]
else: alpha = capillary_loss(l[mask], he_mode, core_radius)
gamma_arr = np.zeros(params.t_num) out = np.zeros_like(l)
else: out[mask] = alpha
gamma_arr = np.ones(params.t_num) * gamma return out
return beta2_coef, gamma_arr, interp_range
@np_cache @np_cache
def dispersion_coefficients( def dispersion_coefficients(
lambda_: np.ndarray, beta2: np.ndarray, w0: float, interp_range=None, deg=8 wl_for_disp: np.ndarray,
beta2_arr: np.ndarray,
w0: float,
interpolation_range=None,
interpolation_degree=8,
): ):
"""Computes the taylor expansion of beta2 to be used in dispersion_op """Computes the taylor expansion of beta2 to be used in dispersion_op
Parameters Parameters
---------- ----------
lambda_ : 1D array wl_for_disp : 1D array
wavelength wavelength
beta2 : 1D array beta2 : 1D array
beta2 as function of lambda_ beta2 as function of wl_for_disp
w0 : float w0 : float
pump angular frequency pump angular frequency
interp_range : slice-like interpolation_range : slice-like
index-style specifying wl range over which to fit to get beta2 coefficients index-style specifying wl range over which to fit to get beta2 coefficients
deg : int interpolation_degree : int
degree of polynomial fit. Will return deg+1 coefficients degree of polynomial fit. Will return deg+1 coefficients
Returns Returns
@@ -839,23 +801,20 @@ def dispersion_coefficients(
Taylor coefficients in decreasing order Taylor coefficients in decreasing order
""" """
logger = get_logger() logger = get_logger()
if interp_range is None: if interpolation_range is None:
r = slice(2, -2) r = slice(2, -2)
else: else:
# 2 discrete gradients are computed before getting to # 2 discrete gradients are computed before getting to
# beta2, so we need to make sure coefficients are not affected # beta2, so we need to make sure coefficients are not affected
# by edge effects # by edge effects
# r = (lambda_ >= max(lambda_[2], interp_range[0])) & ( r = (wl_for_disp >= interpolation_range[0]) & (wl_for_disp <= interpolation_range[1])
# lambda_ <= min(lambda_[-2], interp_range[1])
# )
r = slice(None, None)
logger.debug( logger.debug(
f"interpolating dispersion between {lambda_[r].min()*1e9:.1f}nm and {lambda_[r].max()*1e9:.1f}nm" f"interpolating dispersion between {wl_for_disp[r].min()*1e9:.1f}nm and {wl_for_disp[r].max()*1e9:.1f}nm"
) )
# we get the beta2 Taylor coeffiecients by making a fit around w0 # we get the beta2 Taylor coeffiecients by making a fit around w0
w_c = units.m(lambda_) - w0 w_c = units.m(wl_for_disp) - w0
interp = interp1d(w_c[r], beta2[r]) interp = interp1d(w_c[r], beta2_arr[r])
w_c = np.linspace(w_c[r].min(), w_c[r].max(), len(w_c[r])) w_c = np.linspace(w_c[r].min(), w_c[r].max(), len(w_c[r]))
# import matplotlib.pyplot as plt # import matplotlib.pyplot as plt
@@ -863,15 +822,15 @@ def dispersion_coefficients(
# ax = plt.gca() # ax = plt.gca()
# ax.plot(w_c, interp(w_c) * 1e28) # ax.plot(w_c, interp(w_c) * 1e28)
fit = Chebyshev.fit(w_c, interp(w_c), deg) fit = Chebyshev.fit(w_c, interp(w_c), interpolation_degree)
poly_coef = cheb2poly(fit.convert().coef) poly_coef = cheb2poly(fit.convert().coef)
beta2_coef = poly_coef * np.cumprod([1] + list(range(1, deg + 1))) beta2_coef = poly_coef * np.cumprod([1] + list(range(1, interpolation_degree + 1)))
return beta2_coef return beta2_coef
def dispersion_from_coefficients( def dispersion_from_coefficients(
w_c: np.ndarray, beta: Union[list[float], np.ndarray] w_c: np.ndarray, beta2_coefficients: Iterable[float]
) -> np.ndarray: ) -> np.ndarray:
"""computes the dispersion profile (beta2) from the beta coefficients """computes the dispersion profile (beta2) from the beta coefficients
@@ -879,7 +838,7 @@ def dispersion_from_coefficients(
---------- ----------
w_c : np.ndarray, shape (n, ) w_c : np.ndarray, shape (n, )
centered angular frequency (0 <=> pump frequency) centered angular frequency (0 <=> pump frequency)
beta : Iterable[float] beta2_coefficients : Iterable[float]
beta coefficients beta coefficients
Returns Returns
@@ -888,14 +847,14 @@ def dispersion_from_coefficients(
beta2 as function of w_c beta2 as function of w_c
""" """
coef = np.array(beta) / np.cumprod([1] + list(range(1, len(beta)))) coef = np.array(beta2_coefficients) / np.cumprod([1] + list(range(1, len(beta2_coefficients))))
beta_arr = np.zeros_like(w_c) beta_arr = np.zeros_like(w_c)
for k, b in reversed(list(enumerate(coef))): for k, b in reversed(list(enumerate(coef))):
beta_arr = beta_arr + b * w_c ** k beta_arr = beta_arr + b * w_c ** k
return beta_arr return beta_arr
def delayed_raman_t(t, raman_type="stolen"): def delayed_raman_t(t: np.ndarray, raman_type: str) -> np.ndarray:
""" """
computes the unnormalized temporal Raman response function applied to the array t computes the unnormalized temporal Raman response function applied to the array t
@@ -905,7 +864,6 @@ def delayed_raman_t(t, raman_type="stolen"):
time in the co-moving frame of reference time in the co-moving frame of reference
raman_type : str {"stolen", "agrawal", "measured"} raman_type : str {"stolen", "agrawal", "measured"}
indicates what type of Raman effect modelization to use indicates what type of Raman effect modelization to use
default : "stolen"
Returns Returns
------- -------
@@ -944,7 +902,7 @@ def delayed_raman_t(t, raman_type="stolen"):
return hr_arr return hr_arr
def delayed_raman_w(t, dt, raman_type="stolen"): def delayed_raman_w(t: np.ndarray, dt: float, raman_type: str) -> np.ndarray:
"""returns the delayed raman response function as function of w """returns the delayed raman response function as function of w
see delayed_raman_t for detailes""" see delayed_raman_t for detailes"""
return fft(delayed_raman_t(t, raman_type)) * dt return fft(delayed_raman_t(t, raman_type)) * dt
@@ -1053,7 +1011,7 @@ def _fast_disp_loop(dispersion: np.ndarray, beta_arr, power_fact_arr):
return dispersion return dispersion
def dispersion_op(w_c, beta_arr, where=None): def dispersion_op(w_c, beta2_coefficients, where=None):
""" """
dispersive operator dispersive operator
@@ -1061,7 +1019,7 @@ def dispersion_op(w_c, beta_arr, where=None):
---------- ----------
w_c : 1d array w_c : 1d array
angular frequencies centered around 0 angular frequencies centered around 0
beta_arr : 1d array beta2_coefficients : 1d array
beta coefficients returned by scgenerator.physics.fiber.dispersion_coefficients beta coefficients returned by scgenerator.physics.fiber.dispersion_coefficients
where : indices over which to apply the operatory, otherwise 0 where : indices over which to apply the operatory, otherwise 0
@@ -1072,7 +1030,7 @@ def dispersion_op(w_c, beta_arr, where=None):
dispersion = np.zeros_like(w_c) dispersion = np.zeros_like(w_c)
for k, beta in reversed(list(enumerate(beta_arr))): for k, beta in reversed(list(enumerate(beta2_coefficients))):
dispersion = dispersion + beta * power_fact(w_c, k + 2) dispersion = dispersion + beta * power_fact(w_c, k + 2)
out = np.zeros_like(dispersion) out = np.zeros_like(dispersion)
@@ -1081,19 +1039,19 @@ def dispersion_op(w_c, beta_arr, where=None):
return -1j * out return -1j * out
def _get_radius(radius_param, lambda_=None): def _get_radius(radius_param, wl_for_disp=None):
if isinstance(radius_param, tuple) and lambda_ is not None: if isinstance(radius_param, tuple) and wl_for_disp is not None:
return effective_core_radius(lambda_, *radius_param) return effective_core_radius(wl_for_disp, *radius_param)
else: else:
return radius_param return radius_param
def effective_core_radius(lambda_, core_radius, s=0.08, h=200e-9): def effective_core_radius(wl_for_disp, core_radius, s=0.08, h=200e-9):
"""return the variable core radius according to Eq. S2.2 from Köttig2017 """return the variable core radius according to Eq. S2.2 from Köttig2017
Parameters Parameters
---------- ----------
lambda_ : ndarray, shape (n, ) wl_for_disp : ndarray, shape (n, )
array of wl over which to calculate the effective core radius array of wl over which to calculate the effective core radius
core_radius : float core_radius : float
physical core radius in m physical core radius in m
@@ -1106,20 +1064,22 @@ def effective_core_radius(lambda_, core_radius, s=0.08, h=200e-9):
------- -------
effective_core_radius : ndarray, shape (n, ) effective_core_radius : ndarray, shape (n, )
""" """
return core_radius / (1 + s * lambda_ ** 2 / (core_radius * h)) return core_radius / (1 + s * wl_for_disp ** 2 / (core_radius * h))
def effective_radius_HCARF(core_radius, t, f1, f2, lambda_): def effective_radius_HCARF(core_radius, t, f1, f2, wl_for_disp):
"""eq. 3 in Hasan 2018""" """eq. 3 in Hasan 2018"""
return f1 * core_radius * (1 - f2 * lambda_ ** 2 / (core_radius * t)) return f1 * core_radius * (1 - f2 * wl_for_disp ** 2 / (core_radius * t))
def capillary_loss(lambda_: np.ndarray, he_mode: tuple[int, int], core_radius: float) -> np.ndarray: def capillary_loss(
wl_for_disp: np.ndarray, he_mode: tuple[int, int], core_radius: float
) -> np.ndarray:
"""computes the wavelenth dependent capillary loss according to Marcatili """computes the wavelenth dependent capillary loss according to Marcatili
Parameters Parameters
---------- ----------
lambda_ : np.ndarray, shape (n, ) wl_for_disp : np.ndarray, shape (n, )
wavelength array wavelength array
he_mode : tuple[int, int] he_mode : tuple[int, int]
tuple of mode (n, m) tuple of mode (n, m)
@@ -1131,11 +1091,11 @@ def capillary_loss(lambda_: np.ndarray, he_mode: tuple[int, int], core_radius: f
np.ndarray np.ndarray
loss in 1/m loss in 1/m
""" """
alpha = np.zeros_like(lambda_) alpha = np.zeros_like(wl_for_disp)
mask = lambda_ > 0 mask = wl_for_disp > 0
chi_silica = mat.sellmeier(lambda_[mask], io.load_material_dico("silica")) chi_silica = mat.sellmeier(wl_for_disp[mask], io.load_material_dico("silica"))
nu_n = 0.5 * (chi_silica + 2) / np.sqrt(chi_silica) nu_n = 0.5 * (chi_silica + 2) / np.sqrt(chi_silica)
alpha[mask] = nu_n * (u_nm(*he_mode) * lambda_[mask] / pipi) ** 2 * core_radius ** -3 alpha[mask] = nu_n * (u_nm(*he_mode) * wl_for_disp[mask] / pipi) ** 2 * core_radius ** -3
return alpha return alpha

View File

@@ -5,9 +5,26 @@ from scipy.integrate import cumulative_trapezoid
from ..logger import get_logger from ..logger import get_logger
from . import units from . import units
from .. import io
from .units import NA, c, kB, me, e, hbar from .units import NA, c, kB, me, e, hbar
def n_gas_2(
wl_for_disp: np.ndarray, gas: str, pressure: float, temperature: float, ideal_gas: bool
):
material_dico = io.load_material_dico(gas)
if ideal_gas:
n_gas_2 = sellmeier(wl_for_disp, material_dico, pressure, temperature) + 1
else:
N_1 = number_density_van_der_waals(
pressure=pressure, temperature=temperature, material_dico=material_dico
)
N_0 = number_density_van_der_waals(material_dico=material_dico)
n_gas_2 = sellmeier(wl_for_disp, material_dico) * N_1 / N_0 + 1
return n_gas_2
def pressure_from_gradient(ratio, p0, p1): def pressure_from_gradient(ratio, p0, p1):
"""returns the pressure as function of distance with eq. 20 in Markos et al. (2017) """returns the pressure as function of distance with eq. 20 in Markos et al. (2017)
Parameters Parameters

View File

@@ -100,7 +100,7 @@ class PulseProperties:
return [cls(*a) for a in arr] return [cls(*a) for a in arr]
def initial_field(t, shape, t0, peak_power): def initial_field(t: np.ndarray, shape: str, t0: float, peak_power: float) -> np.ndarray:
"""returns the initial field """returns the initial field
Parameters Parameters
@@ -139,6 +139,7 @@ def modify_field_ratio(
target_power: float = None, target_power: float = None,
target_energy: float = None, target_energy: float = None,
intensity_noise: float = None, intensity_noise: float = None,
noise_correlation: float = 0,
) -> float: ) -> float:
"""multiply a field by this number to get the desired effects """multiply a field by this number to get the desired effects
@@ -165,7 +166,7 @@ def modify_field_ratio(
ratio *= np.sqrt(target_power / abs2(field).max()) ratio *= np.sqrt(target_power / abs2(field).max())
if intensity_noise is not None: if intensity_noise is not None:
d_int, _ = technical_noise(intensity_noise) d_int, _ = technical_noise(intensity_noise, noise_correlation)
ratio *= np.sqrt(d_int) ratio *= np.sqrt(d_int)
return ratio return ratio
@@ -281,6 +282,67 @@ def conform_pulse_params(
return width, t0, peak_power, energy, soliton_num return width, t0, peak_power, energy, soliton_num
def t0_to_width(t0: float, shape: str):
return t0 / fwhm_to_T0_fac[shape]
def width_to_t0(width: float, shape: str):
return width * fwhm_to_T0_fac[shape]
def mean_power_to_energy(mean_power: float, repetition_rate: float) -> float:
return mean_power / repetition_rate
def soliton_num_to_peak_power(soliton_num, beta2, gamma, t0):
return soliton_num ** 2 * abs(beta2) / (gamma * t0 ** 2)
def soliton_num_to_t0(soliton_num, beta2, gamma, peak_power):
return np.sqrt(soliton_num ** 2 * abs(beta2) / (peak_power * gamma))
def soliton_num(L_D, L_NL):
return np.sqrt(L_D / L_NL)
def L_D(t0, beta2):
return t0 ** 2 / abs(beta2)
def L_NL(peak_power, gamma):
return 1 / (gamma * peak_power)
def L_sol(L_D):
return pi / 2 * L_D
def load_previous_spectrum(prev_data_dir: str) -> np.ndarray:
return io.load_last_spectrum(Path(prev_data_dir))[1]
def load_field_file(
field_file: str,
t: np.ndarray,
peak_power: float,
energy: float,
intensity_noise: float,
noise_correlation: float,
) -> np.ndarray:
field_data = np.load(field_file)
field_interp = interp1d(
field_data["time"], field_data["field"], bounds_error=False, fill_value=(0, 0)
)
field_0 = field_interp(t)
field_0 = field_0 * modify_field_ratio(
t, field_0, peak_power, energy, intensity_noise, noise_correlation
)
width, peak_power, energy = measure_field(t, field_0)
return field_0, peak_power, energy, width
def setup_custom_field(params: BareParams) -> bool: def setup_custom_field(params: BareParams) -> bool:
"""sets up a custom field function if necessary and returns """sets up a custom field function if necessary and returns
True if it did so, False otherwise True if it did so, False otherwise

View File

@@ -68,10 +68,12 @@ class RK4IP:
self.w0 = params.w0 self.w0 = params.w0
self.w_power_fact = params.w_power_fact self.w_power_fact = params.w_power_fact
self.alpha = params.alpha self.alpha = params.alpha
self.spec_0 = params.spec_0 self.spec_0 = np.sqrt(params.input_transmission) * params.spec_0
self.z_targets = params.z_targets self.z_targets = params.z_targets
self.z_final = params.length self.z_final = params.length
self.beta = params.beta_func if params.beta_func is not None else params.beta self.beta2_coefficients = (
params.beta_func if params.beta_func is not None else params.beta2_coefficients
)
self.gamma = params.gamma_func if params.gamma_func is not None else params.gamma_arr self.gamma = params.gamma_func if params.gamma_func is not None else params.gamma_arr
self.C_to_A_factor = (params.A_eff_arr / params.A_eff_arr[0]) ** (1 / 4) self.C_to_A_factor = (params.A_eff_arr / params.A_eff_arr[0]) ** (1 / 4)
self.behaviors = params.behaviors self.behaviors = params.behaviors
@@ -92,11 +94,11 @@ class RK4IP:
if self.dynamic_dispersion: if self.dynamic_dispersion:
self.disp = lambda r: fast_dispersion_op( self.disp = lambda r: fast_dispersion_op(
self.w_c, self.beta(r), self.w_power_fact, alpha=self.alpha self.w_c, self.beta2_coefficients(r), self.w_power_fact, alpha=self.alpha
) )
else: else:
self.disp = lambda r: fast_dispersion_op( self.disp = lambda r: fast_dispersion_op(
self.w_c, self.beta, self.w_power_fact, alpha=self.alpha self.w_c, self.beta2_coefficients, self.w_power_fact, alpha=self.alpha
) )
# Set up which quantity is conserved for adaptive step size # Set up which quantity is conserved for adaptive step size

View File

@@ -192,10 +192,10 @@ class PlotRange:
return f"{self.left:.1f}-{self.right:.1f} {self.unit.__name__}" return f"{self.left:.1f}-{self.right:.1f} {self.unit.__name__}"
def beta2_coef(beta): def beta2_coef(beta2_coefficients):
fac = 1e27 fac = 1e27
out = np.zeros_like(beta) out = np.zeros_like(beta2_coefficients)
for i, b in enumerate(beta): for i, b in enumerate(beta2_coefficients):
out[i] = fac * b out[i] = fac * b
fac *= 1e12 fac *= 1e12
return out return out

View File

@@ -21,7 +21,7 @@ from .. import env, math
def fingerprint(params: BareParams): def fingerprint(params: BareParams):
h1 = hash(params.field_0.tobytes()) h1 = hash(params.field_0.tobytes())
h2 = tuple(params.beta) h2 = tuple(params.beta2_coefficients)
return h1, h2 return h1, h2
@@ -93,7 +93,7 @@ def plot_dispersion(config_path: Path, lim: tuple[float, float] = None):
for style, lbl, params in plot_helper(config_path): for style, lbl, params in plot_helper(config_path):
if params.alpha is not None and loss_ax is None: if params.alpha is not None and loss_ax is None:
loss_ax = right.twinx() loss_ax = right.twinx()
if (bbb := tuple(params.beta)) not in already_plotted: if (bbb := tuple(params.beta2_coefficients)) not in already_plotted:
already_plotted.add(bbb) already_plotted.add(bbb)
else: else:
continue continue
@@ -163,7 +163,7 @@ def plot_1_dispersion(
params: BareParams, params: BareParams,
loss: plt.Axes = None, loss: plt.Axes = None,
): ):
beta_arr = fiber.dispersion_from_coefficients(params.w_c, params.beta) beta_arr = fiber.dispersion_from_coefficients(params.w_c, params.beta2_coefficients)
wl = units.m.inv(params.w) wl = units.m.inv(params.w)
D = fiber.beta2_to_D(beta_arr, wl) * 1e6 D = fiber.beta2_to_D(beta_arr, wl) * 1e6
@@ -176,13 +176,13 @@ def plot_1_dispersion(
m = np.ones_like(wl, dtype=bool) m = np.ones_like(wl, dtype=bool)
if lim is None: if lim is None:
lim = params.interp_range lim = params.interpolation_range
m &= wl >= (lim[0] if lim[0] < 1 else lim[0] * 1e-9) m &= wl >= (lim[0] if lim[0] < 1 else lim[0] * 1e-9)
m &= wl <= (lim[1] if lim[1] < 1 else lim[1] * 1e-9) m &= wl <= (lim[1] if lim[1] < 1 else lim[1] * 1e-9)
info_str = ( info_str = (
rf"$\lambda_{{\mathrm{{min}}}}={np.min(params.l[params.l>0])*1e9:.1f}$ nm" rf"$\lambda_{{\mathrm{{min}}}}={np.min(params.l[params.l>0])*1e9:.1f}$ nm"
+ f"\nlower interpolation limit : {params.interp_range[0]*1e9:.1f} nm\n" + f"\nlower interpolation limit : {params.interpolation_range[0]*1e9:.1f} nm\n"
+ f"max time delay : {params.t.max()*1e12:.1f} ps" + f"max time delay : {params.t.max()*1e12:.1f} ps"
) )
@@ -207,7 +207,7 @@ def plot_1_dispersion(
right.plot(1e9 * wl[m], D[m], label=" ", **style) right.plot(1e9 * wl[m], D[m], label=" ", **style)
right.set_ylabel(units.D_ps_nm_km.label) right.set_ylabel(units.D_ps_nm_km.label)
# plot beta # plot beta2
left.plot(units.To.nm(params.w[m]), units.beta2_fs_cm.inv(beta_arr[m]), label=" ", **style) left.plot(units.To.nm(params.w[m]), units.beta2_fs_cm.inv(beta_arr[m]), label=" ", **style)
left.set_ylabel(units.beta2_fs_cm.label) left.set_ylabel(units.beta2_fs_cm.label)

View File

@@ -1,19 +1,23 @@
from collections import defaultdict
from typing import Any, Callable, Union
from typing import TypeVar, Optional
from dataclasses import dataclass
import numpy as np
import itertools import itertools
from functools import wraps
import re import re
from collections import defaultdict
from dataclasses import dataclass
from typing import Any, Callable, Optional, TypeVar, Union
import numpy as np
from ..physics import fiber, pulse, materials
from .. import math from .. import math
from ..logger import get_logger
from ..physics import fiber, materials, pulse, units
T = TypeVar("T") T = TypeVar("T")
import inspect import inspect
class EvaluatorError(Exception):
pass
class Rule: class Rule:
def __init__( def __init__(
self, self,
@@ -21,6 +25,7 @@ class Rule:
func: Callable, func: Callable,
args: list[str] = None, args: list[str] = None,
priorities: Union[int, list[int]] = None, priorities: Union[int, list[int]] = None,
conditions: dict[str, str] = None,
): ):
targets = list(target) if isinstance(target, (list, tuple)) else [target] targets = list(target) if isinstance(target, (list, tuple)) else [target]
self.func = func self.func = func
@@ -32,6 +37,7 @@ class Rule:
if args is None: if args is None:
args = get_arg_names(func) args = get_arg_names(func)
self.args = args self.args = args
self.conditions = conditions or {}
def __repr__(self) -> str: def __repr__(self) -> str:
return f"Rule(targets={self.targets!r}, func={self.func!r}, args={self.args!r})" return f"Rule(targets={self.targets!r}, func={self.func!r}, args={self.args!r})"
@@ -96,6 +102,7 @@ class Evaluator:
self.params = {} self.params = {}
self.__curent_lookup = set() self.__curent_lookup = set()
self.eval_stats: dict[str, EvalStat] = defaultdict(EvalStat) self.eval_stats: dict[str, EvalStat] = defaultdict(EvalStat)
self.logger = get_logger(__name__)
def append(self, *rule: Rule): def append(self, *rule: Rule):
for r in rule: for r in rule:
@@ -128,7 +135,7 @@ class Evaluator:
Raises Raises
------ ------
RecursionError EvaluatorError
a cyclic dependence exists a cyclic dependence exists
KeyError KeyError
there is no saved rule for the target there is no saved rule for the target
@@ -136,7 +143,7 @@ class Evaluator:
value = self.params.get(target) value = self.params.get(target)
if value is None: if value is None:
if target in self.__curent_lookup: if target in self.__curent_lookup:
raise RecursionError( raise EvaluatorError(
"cyclic dependency detected : " "cyclic dependency detected : "
f"{target!r} seems to depend on itself, " f"{target!r} seems to depend on itself, "
f"please provide a value for at least one variable in {self.__curent_lookup}" f"please provide a value for at least one variable in {self.__curent_lookup}"
@@ -144,28 +151,36 @@ class Evaluator:
else: else:
self.__curent_lookup.add(target) self.__curent_lookup.add(target)
if len(self.rules[target]) == 0:
raise EvaluatorError(f"no rule for {target}")
error = None error = None
for rule in reversed(self.rules[target]): for ii, rule in enumerate(
filter(lambda r: self.validate_condition(r), reversed(self.rules[target]))
):
self.logger.debug(f"attempt {ii+1} to compute {target}, this time using {rule!r}")
try: try:
args = [self.compute(k) for k in rule.args] args = [self.compute(k) for k in rule.args]
returned_values = rule.func(*args) returned_values = rule.func(*args)
if len(rule.targets) == 1: if len(rule.targets) == 1:
self.params[target] = returned_values returned_values = [returned_values]
self.eval_stats[target].priority = rule.targets[target] for ((param_name, param_priority), returned_value) in zip(
value = returned_values rule.targets.items(), returned_values
else:
for ((k, p), v) in zip(rule.targets.items(), returned_values):
if (
k == target
or k not in self.params
or self.eval_stats[k].priority < p
): ):
self.params[k] = v if (
self.eval_stats[k] = p param_name == target
if k == target: or param_name not in self.params
value = v or self.eval_stats[param_name].priority < param_priority
):
self.logger.info(
f"computed {param_name}={returned_value} using {rule.func.__name__} from {rule.func.__module__}"
)
self.params[param_name] = returned_value
self.eval_stats[param_name] = param_priority
if param_name == target:
value = returned_value
break break
except (RecursionError, KeyError) as e: except (EvaluatorError, KeyError) as e:
error = e error = e
continue continue
@@ -175,6 +190,9 @@ class Evaluator:
self.__curent_lookup.remove(target) self.__curent_lookup.remove(target)
return value return value
def validate_condition(self, rule: Rule) -> bool:
return all(self.compute(k) == v for k, v in rule.conditions.items())
def __call__(self, target: str, args: list[str] = None): def __call__(self, target: str, args: list[str] = None):
"""creates a wrapper that adds decorated functions to the set of rules """creates a wrapper that adds decorated functions to the set of rules
@@ -220,105 +238,94 @@ def func_rewrite(func: Callable, kwarg_names: list[str], arg_names: list[str] =
func_str = f"def {tmp_name}({sign_arg_str}):\n return __func__({call_arg_str})" func_str = f"def {tmp_name}({sign_arg_str}):\n return __func__({call_arg_str})"
scope = dict(__func__=func) scope = dict(__func__=func)
exec(func_str, scope) exec(func_str, scope)
return scope[tmp_name] out_func = scope[tmp_name]
out_func.__module__ = "evaluator"
return out_func
default_rules: list[Rule] = [ default_rules: list[Rule] = [
# Grid
*Rule.deduce( *Rule.deduce(
["z_targets", "t", "time_window", "t_num", "dt", "w_c", "w0", "w", "w_power_fact", "l"], ["z_targets", "t", "time_window", "t_num", "dt", "w_c", "w0", "w", "w_power_fact", "l"],
math.build_sim_grid, math.build_sim_grid,
["time_window", "t_num", "dt"], ["time_window", "t_num", "dt"],
2, 2,
) ),
] # Pulse
""" Rule("spec_0", np.fft.fft, ["field_0"]),
Rule("gamma", fiber.gamma_parameter), Rule("field_0", np.fft.ifft, ["spec_0"]),
Rule("spec_0", pulse.load_previous_spectrum, priorities=3),
Rule(
["field_0", "peak_power", "energy", "width"], pulse.load_field_file, priorities=[2, 1, 1, 1]
),
Rule("field_0", pulse.initial_field, priorities=1),
Rule("peak_power", pulse.E0_to_P0, ["energy", "t0", "shape"]),
Rule("peak_power", pulse.soliton_num_to_peak_power),
Rule("energy", pulse.P0_to_E0, ["peak_power", "t0", "shape"]),
Rule("energy", pulse.mean_power_to_energy),
Rule("t0", pulse.width_to_t0),
Rule("t0", pulse.soliton_num_to_t0),
Rule("width", pulse.t0_to_width),
Rule("soliton_num", pulse.soliton_num),
Rule("L_D", pulse.L_D),
Rule("L_NL", pulse.L_NL),
Rule("L_sol", pulse.L_sol),
# Fiber Dispersion
Rule("wl_for_disp", fiber.lambda_for_dispersion),
Rule("w_for_disp", units.m, ["wl_for_disp"]),
Rule(
"beta2_coefficients",
fiber.dispersion_coefficients,
["wl_for_disp", "beta2_arr", "w0", "interpolation_range", "interpolation_degree"],
),
Rule("beta2_arr", fiber.beta2),
Rule("beta2_arr", fiber.dispersion_from_coefficients),
Rule("beta2", lambda beta2_coefficients: beta2_coefficients[0]),
Rule(
["wl_for_disp", "beta2_arr", "interpolation_range"],
fiber.load_custom_dispersion,
priorities=[2, 2, 2],
),
Rule("hr_w", fiber.delayed_raman_w),
Rule("n_eff", fiber.n_eff_hasan, conditions=dict(model="hasan")),
Rule("n_eff", fiber.n_eff_marcatili, conditions=dict(model="marcatili")),
Rule("n_eff", fiber.n_eff_marcatili_adjusted, conditions=dict(model="marcatili_adjusted")),
Rule(
"n_eff",
fiber.n_eff_pcf,
["wl_for_disp", "pitch", "pitch_ratio"],
conditions=dict(model="pcf"),
),
Rule("capillary_spacing", fiber.HCARF_gap),
# Fiber nonlinearity
Rule("A_eff", fiber.A_eff_from_V),
Rule("A_eff", fiber.A_eff_from_diam),
Rule("A_eff", fiber.A_eff_hasan, conditions=dict(model="hasan")),
Rule("A_eff", fiber.A_eff_from_gamma, priorities=-1),
Rule("A_eff_arr", fiber.A_eff_from_V, ["core_radius", "V_eff_arr"]),
Rule("A_eff_arr", fiber.load_custom_A_eff),
Rule("A_eff_arr", fiber.constant_A_eff_arr, priorities=-1),
Rule(
"V_eff",
fiber.V_parameter_koshiba,
["wavelength", "pitch", "pitch_ratio"],
conditions=dict(model="pcf"),
),
Rule("V_eff", fiber.V_eff_marcuse, ["wavelength", "core_radius", "numerical_aperture"]),
Rule("V_eff_arr", fiber.V_parameter_koshiba, conditions=dict(model="pcf")),
Rule("V_eff_arr", fiber.V_eff_marcuse),
Rule("gamma", lambda gamma_arr: gamma_arr[0]), Rule("gamma", lambda gamma_arr: gamma_arr[0]),
Rule(["beta", "gamma", "interp_range"], fiber.PCF_dispersion), Rule("gamma_arr", fiber.gamma_parameter, ["n2", "w0", "A_eff_arr"]),
Rule("n2"), # Fiber loss
Rule("loss"), Rule("alpha", fiber.compute_capillary_loss),
Rule("loss_file"), Rule("alpha", fiber.load_custom_loss),
Rule("effective_mode_diameter"), # gas
Rule("A_eff"), Rule("n_gas_2", materials.n_gas_2),
Rule("A_eff_file"),
Rule("pitch"),
Rule("pitch_ratio"),
Rule("core_radius"),
Rule("he_mode"),
Rule("fit_parameters"),
Rule("beta"),
Rule("dispersion_file"),
Rule("model"),
Rule("length"),
Rule("capillary_num"),
Rule("capillary_outer_d"),
Rule("capillary_thickness"),
Rule("capillary_spacing"),
Rule("capillary_resonance_strengths"),
Rule("capillary_nested"),
Rule("gas_name"),
Rule("pressure"),
Rule("temperature"),
Rule("plasma_density"),
Rule("field_file"),
Rule("repetition_rate"),
Rule("peak_power"),
Rule("mean_power"),
Rule("energy"),
Rule("soliton_num"),
Rule("quantum_noise"),
Rule("shape"),
Rule("wavelength"),
Rule("intensity_noise"),
Rule("width"),
Rule("t0"),
Rule("behaviors"),
Rule("parallel"),
Rule("raman_type"),
Rule("ideal_gas"),
Rule("repeat"),
Rule("t_num"),
Rule("z_num"),
Rule("time_window"),
Rule("dt"),
Rule("tolerated_error"),
Rule("step_size"),
Rule("lower_wavelength_interp_limit"),
Rule("upper_wavelength_interp_limit"),
Rule("interpolation_degree"),
Rule("prev_sim_dir"),
Rule("recovery_last_stored"),
Rule("worker_num"),
Rule("field_0"),
Rule("spec_0"),
Rule("alpha"),
Rule("gamma_arr"),
Rule("A_eff_arr"),
Rule("w"),
Rule("l"),
Rule("w_c"),
Rule("w0"),
Rule("w_power_fact"),
Rule("t"),
Rule("L_D"),
Rule("L_NL"),
Rule("L_sol"),
Rule("dynamic_dispersion"),
Rule("adapt_step_size"),
Rule("error_ok"),
Rule("hr_w"),
Rule("z_targets"),
Rule("const_qty"),
Rule("beta_func"),
Rule("gamma_func"),
Rule("interp_range"),
Rule("datetime"),
Rule("version"),
] ]
"""
def main(): def main():
import matplotlib.pyplot as plt
evalor = Evaluator() evalor = Evaluator()
evalor.append(*default_rules) evalor.append(*default_rules)
@@ -328,13 +335,29 @@ def main():
"z_num": 128, "z_num": 128,
"wavelength": 1500e-9, "wavelength": 1500e-9,
"interpolation_degree": 8, "interpolation_degree": 8,
"interpolation_range": (500e-9, 2200e-9),
"t_num": 16384, "t_num": 16384,
"dt": 1e-15, "dt": 1e-15,
"shape": "gaussian",
"repetition_rate": 40e6,
"width": 30e-15,
"mean_power": 100e-3,
"n2": 2.4e-20,
"A_eff_file": "/Users/benoitsierro/Nextcloud/PhD/Supercontinuum/PCF Simulations/PM2000D/PM2000D_A_eff_max.npz",
"model": "pcf",
"pitch": 1.2e-6,
"pitch_ratio": 0.5,
} }
) )
evalor.compute("z_targets") evalor.compute("z_targets")
print(evalor.params.keys()) print(evalor.params.keys())
print(evalor.params["l"][evalor.params["l"] > 0].min()) print(evalor.params["l"][evalor.params["l"] > 0].min())
evalor.compute("spec_0")
plt.plot(evalor.params["l"], abs(evalor.params["spec_0"]) ** 2)
plt.show()
print(evalor.compute("gamma"))
print(evalor.compute("beta2"))
from pprint import pprint
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -288,7 +288,7 @@ valid_variable = {
"field_file", "field_file",
"loss_file", "loss_file",
"A_eff_file", "A_eff_file",
"beta", "beta2_coefficients",
"gamma", "gamma",
"pitch", "pitch",
"pitch_ratio", "pitch_ratio",
@@ -369,7 +369,7 @@ class BareParams:
core_radius: float = Parameter(in_range_excl(0, 1e-3)) core_radius: float = Parameter(in_range_excl(0, 1e-3))
he_mode: Tuple[int, int] = Parameter(int_pair, default=(1, 1)) he_mode: Tuple[int, int] = Parameter(int_pair, default=(1, 1))
fit_parameters: Tuple[int, int] = Parameter(int_pair, default=(0.08, 200e-9)) fit_parameters: Tuple[int, int] = Parameter(int_pair, default=(0.08, 200e-9))
beta: Iterable[float] = Parameter(num_list) beta2_coefficients: Iterable[float] = Parameter(num_list)
dispersion_file: str = Parameter(string) dispersion_file: str = Parameter(string)
model: str = Parameter( model: str = Parameter(
literal("pcf", "marcatili", "marcatili_adjusted", "hasan", "custom"), default="custom" literal("pcf", "marcatili", "marcatili_adjusted", "hasan", "custom"), default="custom"
@@ -420,10 +420,7 @@ class BareParams:
dt: float = Parameter(in_range_excl(0, 5e-15)) dt: float = Parameter(in_range_excl(0, 5e-15))
tolerated_error: float = Parameter(in_range_excl(1e-15, 1e-3), default=1e-11) tolerated_error: float = Parameter(in_range_excl(1e-15, 1e-3), default=1e-11)
step_size: float = Parameter(positive(float, int)) step_size: float = Parameter(positive(float, int))
lower_wavelength_interp_limit: float = Parameter(in_range_incl(100e-9, 3000e-9), default=100e-9) interpolation_range: Tuple[float, float] = Parameter(float_pair)
upper_wavelength_interp_limit: float = Parameter(
in_range_incl(200e-9, 5000e-9), default=2000e-9
)
interpolation_degree: int = Parameter(positive(int), default=8) interpolation_degree: int = Parameter(positive(int), default=8)
prev_sim_dir: str = Parameter(string) prev_sim_dir: str = Parameter(string)
recovery_last_stored: int = Parameter(non_negative(int), default=0) recovery_last_stored: int = Parameter(non_negative(int), default=0)
@@ -432,11 +429,13 @@ class BareParams:
# computed # computed
field_0: np.ndarray = Parameter(type_checker(np.ndarray)) field_0: np.ndarray = Parameter(type_checker(np.ndarray))
spec_0: np.ndarray = Parameter(type_checker(np.ndarray)) spec_0: np.ndarray = Parameter(type_checker(np.ndarray))
beta2: float = Parameter(type_checker(int, float))
alpha: np.ndarray = Parameter(type_checker(np.ndarray)) alpha: np.ndarray = Parameter(type_checker(np.ndarray))
gamma_arr: np.ndarray = Parameter(type_checker(np.ndarray)) gamma_arr: np.ndarray = Parameter(type_checker(np.ndarray))
A_eff_arr: np.ndarray = Parameter(type_checker(np.ndarray)) A_eff_arr: np.ndarray = Parameter(type_checker(np.ndarray))
w: np.ndarray = Parameter(type_checker(np.ndarray)) w: np.ndarray = Parameter(type_checker(np.ndarray))
l: np.ndarray = Parameter(type_checker(np.ndarray)) l: np.ndarray = Parameter(type_checker(np.ndarray))
# wl_for_disp: np.ndarray = Parameter(type_checker(np.ndarray))
w_c: np.ndarray = Parameter(type_checker(np.ndarray)) w_c: np.ndarray = Parameter(type_checker(np.ndarray))
w0: float = Parameter(positive(float)) w0: float = Parameter(positive(float))
w_power_fact: np.ndarray = Parameter(validator_list(type_checker(np.ndarray))) w_power_fact: np.ndarray = Parameter(validator_list(type_checker(np.ndarray)))
@@ -452,7 +451,6 @@ class BareParams:
const_qty: np.ndarray = Parameter(type_checker(np.ndarray)) const_qty: np.ndarray = Parameter(type_checker(np.ndarray))
beta_func: Callable[[float], List[float]] = Parameter(func_validator) beta_func: Callable[[float], List[float]] = Parameter(func_validator)
gamma_func: Callable[[float], float] = Parameter(func_validator) gamma_func: Callable[[float], float] = Parameter(func_validator)
interp_range: Tuple[float, float] = Parameter(float_pair)
datetime: datetime_module.datetime = Parameter(type_checker(datetime_module.datetime)) datetime: datetime_module.datetime = Parameter(type_checker(datetime_module.datetime))
version: str = Parameter(string) version: str = Parameter(string)
@@ -482,6 +480,7 @@ class BareParams:
"t", "t",
"z_targets", "z_targets",
"l", "l",
"wl_for_disp",
"alpha", "alpha",
"gamma_arr", "gamma_arr",
"A_eff_arr", "A_eff_arr",

View File

@@ -13,10 +13,8 @@ wavelength = 1050e-9
# simulation # simulation
behaviors = ["spm", "raman", "ss"] behaviors = ["spm", "raman", "ss"]
lower_wavelength_interp_limit = 300e-9
raman_type = "agrawal" raman_type = "agrawal"
t_num = 16384 t_num = 16384
time_window = 37e-12 time_window = 37e-12
tolerated_error = 1e-11 tolerated_error = 1e-11
upper_wavelength_interp_limit = 1900e-9
z_num = 128 z_num = 128

View File

@@ -12,12 +12,11 @@ quantum_noise = false
# simulation # simulation
behaviors = ["spm", "raman", "ss"] behaviors = ["spm", "raman", "ss"]
lower_wavelength_interp_limit = 300e-9 interpolation_range = [300e-9, 1900e-9]
raman_type = "agrawal" raman_type = "agrawal"
t_num = 16384 t_num = 16384
time_window = 37e-12 time_window = 37e-12
tolerated_error = 1e-11 tolerated_error = 1e-11
upper_wavelength_interp_limit = 1900e-9
z_num = 128 z_num = 128
[variable] [variable]

View File

@@ -1,7 +1,17 @@
name = "fiber 2" name = "fiber 2"
# fiber # fiber
beta = [-1.183e-26, 8.1038e-41, -9.5205e-56, 2.0737e-70, -5.3943e-85, 1.3486e-99, -2.5495e-114, 3.0524e-129, -1.714e-144] beta2_coefficients = [
-1.183e-26,
8.1038e-41,
-9.5205e-56,
2.0737e-70,
-5.3943e-85,
1.3486e-99,
-2.5495e-114,
3.0524e-129,
-1.714e-144,
]
gamma = 0.13 gamma = 0.13
length = 0.05 length = 0.05
model = "custom" model = "custom"

View File

@@ -1,7 +1,17 @@
name = "full anomalous" name = "full anomalous"
# fiber # fiber
beta = [-1.183e-26, 8.1038e-41, -9.5205e-56, 2.0737e-70, -5.3943e-85, 1.3486e-99, -2.5495e-114, 3.0524e-129, -1.714e-144] beta2_coefficients = [
-1.183e-26,
8.1038e-41,
-9.5205e-56,
2.0737e-70,
-5.3943e-85,
1.3486e-99,
-2.5495e-114,
3.0524e-129,
-1.714e-144,
]
gamma = 0.11 gamma = 0.11
input_transmission = 1.0 input_transmission = 1.0
length = 0.02 length = 0.02
@@ -19,13 +29,12 @@ behaviors = ["spm", "ss"]
dt = 1e-15 dt = 1e-15
frep = 80000000.0 frep = 80000000.0
ideal_gas = false ideal_gas = false
lower_wavelength_interp_limit = 3e-7 interpolation_range = [3e-7, 1.9e-6]
parallel = true parallel = true
raman_type = "measured" raman_type = "measured"
repeat = 3 repeat = 3
t_num = 16384 t_num = 16384
tolerated_error = 1e-9 tolerated_error = 1e-9
upper_wavelength_interp_limit = 1.9e-6
z_num = 64 z_num = 64
[variable] [variable]

View File

@@ -1,7 +1,7 @@
name = "full anomalous" name = "full anomalous"
# fiber # fiber
beta = [ beta2_coefficients = [
-1.183e-26, -1.183e-26,
8.1038e-41, 8.1038e-41,
-9.5205e-56, -9.5205e-56,

View File

@@ -3,7 +3,7 @@
name = "test config" name = "test config"
# fiber # fiber
beta = [1, 2, 3] beta2_coefficients = [1, 2, 3]
gamma = 0.018 gamma = 0.018
length = 1 length = 1

View File

@@ -143,20 +143,6 @@ class TestInitializeMethods(unittest.TestCase):
init.Config(**conf("good5")).__dict__.items(), init.Config(**conf("good5")).__dict__.items(),
) )
self.assertLessEqual(
dict(
t_num=16384,
time_window=37e-12,
lower_wavelength_interp_limit=defaults.default_parameters[
"lower_wavelength_interp_limit"
],
upper_wavelength_interp_limit=defaults.default_parameters[
"upper_wavelength_interp_limit"
],
).items(),
init.Config(**conf("good6")).__dict__.items(),
)
def setup_conf_custom_field(self, path) -> BareParams: def setup_conf_custom_field(self, path) -> BareParams:
conf = load_conf(path) conf = load_conf(path)