diff --git a/README.md b/README.md index 09f8f1e..f8b2199 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ effective_mode_diameter = 10.1e-6 name = "PM2000D_2" length = 0.01 n2 = 3.4e-20 -A_eff_file = "PM2000D/PM2000D_A_eff_marcuse.npz" +effective_area_file = "PM2000D/PM2000D_A_eff_marcuse.npz" dispersion_file = "PM2000D/Dispersion/PM2000D_1 extrapolated 0 4.npz" [Fiber.variable] # this variable parameter will be applied to PM2000D_2 @@ -133,9 +133,9 @@ and specify the parameters it needs pcf : -pitch: float +pcf_pitch: float distance between air holes in m -pitch_ratio: float 0.2 < pitch_ratio < 0.8 +pcf_pitch_ratio: float 0.2 < pcf_pitch_ratio < 0.8 ratio hole diameter/pich marcatili, marcatili_adjusted, hasan : @@ -189,11 +189,11 @@ effective_mode_diameter : float, optional n2 : float, optional non linear refractive index in m^2/W -A_eff : float, optional +effective_area : float, optional effective mode field area -A_eff_file : str, optional - file containing an A_eff array (in m^2) as function of a wavelength array (in m) +effective_area_file : str, optional + file containing an effective_area array (in m^2) as function of a wavelength array (in m) length: float, optional length of the fiber in m. default : 1 diff --git a/developement_help.md b/developement_help.md deleted file mode 100755 index 4e2bbd4..0000000 --- a/developement_help.md +++ /dev/null @@ -1,25 +0,0 @@ -## add parameter -- add it to ```utils.parameters``` -- add it to README.md -- add the necessary Rules in ```utils.parameters``` -- optional : add a default value -- optional : add to mandatory_parameters - -## complicated Rule conditions -- add the desired parameters to the init of the operator -- raise OperatorError if the conditions are not met - -## operators -There are 3 kinds of operators -- `SpecOperator(spec: np.ndarray, z: float) -> np.ndarray` : operate on the spectrum - - Envelope nonlinear operator used in the solver - - Full field nonlinear operator used in the solver -- `FieldOperator(field: np.ndarray, z: float) -> np.ndarray` : operate on the field - - SPM - - Raman - - Ionization -- `VariableQuantity(z: float) -> float | np.ndarray` : return the value of a certain quantity along the fiber depending on z - - dispersion - - refractive index - - full field nonlinear prefactor - - nonlinear parameter (chi3, n2, gamma) diff --git a/examples/Optica_PM2000D/Optica_PM2000D.toml b/examples/Optica_PM2000D/Optica_PM2000D.toml index 14e5e3f..2e99638 100755 --- a/examples/Optica_PM2000D/Optica_PM2000D.toml +++ b/examples/Optica_PM2000D/Optica_PM2000D.toml @@ -12,7 +12,7 @@ z_num = 128 length = 0.3 dispersion_file = "PM2000D_2 extrapolated 4 0.npz" interpolation_degree = 12 -A_eff_file = "PM2000D_A_eff_marcuse.npz" +effective_area_file = "PM2000D_A_eff_marcuse.npz" n2 = 4.5e-20 diff --git a/playground.py b/playground.py new file mode 100644 index 0000000..e0f3028 --- /dev/null +++ b/playground.py @@ -0,0 +1,57 @@ +from __future__ import annotations + +import inspect +import os + +import numpy as np + + +def make_grid( + dt: float | None = None, + period: float | None = None, + t_num: float | None = None, + wl_min: float | None = None, +): + ... + + +class Root: + dt: float = Param() + period: float + t_num: int + + fiber: Fiber + pulses: PulseTrain + + def __init__(self, name: str): + ... + + @dt.register + def dt_from_lmin(wavelength_max: float, wavelength_pump: float): + return 1 / 6e8 * 1 / (1 / wavelength_pump - 1 / wavelength_max) + + +class PulseTrain: + pulse_width: float + shape: str = "gaussian" + peak_power: float + quantum_noise: bool = True + + def load_noise_spectrum(self, path: os.PathLike): + ... + + +class Fiber: + beta2_arr: np.ndarray + length: float + + +params = Root(dt=2e-15, t_num=1024) + +pulses = params.pulse_train +pulses.pulse_width = 50e-15 +pulses.shape = "sech" +pulses.load_noise_spectrum(dBm="./some_noise.csv", v_ref=3) + +fiber = params.fiber +fiber.length = 0.2 diff --git a/src/scgenerator/data/default_params.json b/src/scgenerator/data/default_params.json deleted file mode 100644 index fd9105c..0000000 --- a/src/scgenerator/data/default_params.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "lambda0": 835e-9, - "P0": 10e3, - "T0": 28.4e-15, - "z_targets": [0, 1, 128], - "chirp": 0, - "alpha": 0, - "fiber_type": "PCF", - "pitch": 1.55e-6, - "pitch_ratio": 0.37, - "gamma": 0.11, - "pulse_shape":"gaussian", - "dt": 1e-15, - "nt": 16384, - "frep": 80e6, - "behaviors": ["spm", "ss", "raman"], - "raman_rf": "stolen", - "adapt_step_size": true, - "error_ok": 1e-8, - "vmin_log": -40 - } diff --git a/src/scgenerator/data/gas.json b/src/scgenerator/data/gas.json deleted file mode 100644 index cc59047..0000000 --- a/src/scgenerator/data/gas.json +++ /dev/null @@ -1,198 +0,0 @@ -{ - "air": { - "sellmeier": { - "B": [57921050000.0, 1679170000.0], - "C": [238018500000000.0, 57362000000000.0], - "kind": 2, - "P0": 101325, - "T0": 288.15 - } - }, - "nitrogen": { - "a": 0.137, - "b": 1.709e-05, - "sellmeier": { - "B": [32431570000.0], - "C": [144000000000000.0], - "kind": 2, - "P0": 101325, - "T0": 273.15, - "const": 6.8552e-05 - }, - "kerr": { - "source": "Wahlstrand, J. K., Cheng, Y. H., & Milchberg, H. M. (2012). High field optical nonlinearity and the Kramers-Kronig relations. Physical review letters, 109(11), 113904.", - "P0": 30.4e3, - "T0": 273.15, - "n2": 2.2e-23 - } - - }, - "helium": { - "a": 0.00346, - "b": 2.38e-05, - "sellmeier": { - "source": "A. Ermolov, K. F. Mak, M. H. Frosz, J. C. Travers, P. St. J. Russell, Supercontinuum generation in the vacuum ultraviolet through dispersive-wave and soliton-plasma interaction in a noble-gas-filled hollow-core photonic crystal fiber, Phys. Rev. A 92, 033821 (2015)", - "B": [2.16463842e-5, 2.10561127e-7, 4.7509272e-5], - "C": [-6.80769781e-16, 5.13251289e-15, 3.18621354e-15], - "kind": 1, - "P0": 101325, - "T0": 273.15 - }, - "kerr": { - "source": "Wahlstrand, J. K., Cheng, Y. H., & Milchberg, H. M. (2012). High field optical nonlinearity and the Kramers-Kronig relations. Physical review letters, 109(11), 113904.", - "P0": 30.4e3, - "T0": 273.15, - "n2": 3.1e-25 - } - - }, - "helium_alt": { - "a": 0.00346, - "b": 2.38e-05, - "sellmeier": { - "source": " C. Cuthbertson and M. Cuthbertson. The refraction and dispersion of neon and helium. Proc. R. Soc. London A 135, 40-47 (1936)", - "B": [14755297000.0], - "C": [426297400000000.0], - "kind": 2, - "P0": 101325, - "T0": 273.15 - }, - "kerr": { - "P0": 30.4e3, - "T0": 273.15, - "n2": 3.1e-25 - } - - }, - "hydrogen": { - "a": 0.02453, - "b": 2.651e-05, - "sellmeier": { - "source": "E. R. Peck and S. Hung. Refractivity and dispersion of hydrogen in the visible and near infrared, J. Opt. Soc. Am. 67, 1550-1554 (1977)", - "B": [0.0148956, 0.0049037], - "C": [180.7e-12, 92e-12], - "kind": 2, - "P0": 101325, - "T0": 273.15 - }, - "kerr": { - "source": "Shelton, D. P., & Rice, J. E. (1994). Measurements and calculations of the hyperpolarizabilities of atoms and small molecules in the gas phase. Chemical Reviews, 94(1), 3-29", - "P0": 30.4e3, - "T0": 273.15, - "n2": 6.36e-24 - } - - }, - "neon": { - "a": 0.02135, - "b": 1.709e-05, - "sellmeier": { - "B": [1281450000.0, 22048600000.0], - "C": [184661000000000.0, 376840000000000.0], - "kind": 2, - "P0": 101325, - "T0": 273.15 - }, - "kerr": { - "source": "Wahlstrand, J. K., Cheng, Y. H., & Milchberg, H. M. (2012). High field optical nonlinearity and the Kramers-Kronig relations. Physical review letters, 109(11), 113904.", - "P0": 30.4e3, - "T0": 273.15, - "n2": 8.7e-25 - } - - }, - "argon": { - "a": 0.1355, - "b": 3.201e-05, - "sellmeier": { - "source": "A. Bideau-Mehu, Y. Guern, R. Abjean, A. Johannin-Gilles. Measurement of refractive indices of neon, argon, krypton and xenon in the 253.7-140.4 nm wavelength range. Dispersion relations and estimated oscillator strengths of the resonance lines. J. Quant. Spectrosc. Rad. Transfer 25, 395-402 (1981)", - "B": [2501410000.0, 500283000.0, 52234300000.0], - "C": [91012000000000.0, 87892000000000.0, 214020000000000.0], - "kind": 2, - "P0": 101325, - "T0": 273.15 - }, - "kerr": { - "source": "Wahlstrand, J. K., Cheng, Y. H., & Milchberg, H. M. (2012). High field optical nonlinearity and the Kramers-Kronig relations. Physical review letters, 109(11), 113904.", - "P0": 30.4e3, - "T0": 273.15, - "n2": 9.7e-24 - } - - }, - "argon_alt": { - "a": 0.1355, - "b": 3.201e-05, - "sellmeier": { - "source": "A. Börzsönyi, Z. Heiner, M. P. Kalashnikov, A. P. Kovács, and K. Osvay, Dispersion measurement of inert gases and gas mixtures at 800 nm, Appl. Opt. 47, 4856-4863 (2008)", - "B": [20332.29e-8, 34458.31e-8], - "C": [206.12e-18, 8.066e-15], - "kind": 1, - "P0": 101325, - "T0": 273.15 - }, - "kerr": { - "source": "Wahlstrand, J. K., Cheng, Y. H., & Milchberg, H. M. (2012). High field optical nonlinearity and the Kramers-Kronig relations. Physical review letters, 109(11), 113904.", - "P0": 30.4e3, - "T0": 273.15, - "n2": 9.7e-24 - } - - }, - "argon_alt2": { - "a": 0.1355, - "b": 3.201e-05, - "sellmeier": { - "source": "E. R. Peck and D. J. Fisher. Dispersion of argon, J. Opt. Soc. Am. 54, 1362-1364 (1964)", - "B": [3.0182943e-2], - "C": [144e12], - "const": 6.7867e-5, - "kind": 2, - "P0": 101325, - "T0": 273.15 - }, - "kerr": { - "source": "Wahlstrand, J. K., Cheng, Y. H., & Milchberg, H. M. (2012). High field optical nonlinearity and the Kramers-Kronig relations. Physical review letters, 109(11), 113904.", - "P0": 30.4e3, - "T0": 273.15, - "n2": 9.7e-24 - } - - }, - "krypton": { - "a": 0.2349, - "b": 3.978e-05, - "sellmeier": { - "B": [2536370000.0, 2736490000.0, 62080200000.0], - "C": [65474200000000.0, 73698000000000.0, 181080000000000.0], - "kind": 2, - "P0": 101325, - "T0": 273.15 - }, - "kerr": { - "source": "Wahlstrand, J. K., Cheng, Y. H., & Milchberg, H. M. (2012). High field optical nonlinearity and the Kramers-Kronig relations. Physical review letters, 109(11), 113904.", - "P0": 30.4e3, - "T0": 273.15, - "n2": 2.2e-23 - } - - }, - "xenon": { - "a": 0.425, - "b": 5.105e-05, - "sellmeier": { - "B": [3228690000.0, 3553930000.0, 60676400000.0], - "C": [46301000000000.0, 59578000000000.0, 112740000000000.0], - "kind": 2, - "P0": 101325, - "T0": 273.15 - }, - "kerr": { - "source": "Wahlstrand, J. K., Cheng, Y. H., & Milchberg, H. M. (2012). High field optical nonlinearity and the Kramers-Kronig relations. Physical review letters, 109(11), 113904.", - "P0": 30.4e3, - "T0": 273.15, - "n2": 5.8e-23 - } - - } -} \ No newline at end of file diff --git a/src/scgenerator/evaluator.py b/src/scgenerator/evaluator.py index d099e1b..603e324 100644 --- a/src/scgenerator/evaluator.py +++ b/src/scgenerator/evaluator.py @@ -318,8 +318,6 @@ default_rules: list[Rule] = [ Rule(["input_time", "input_field"], pulse.load_custom_field), Rule("spec_0", lambda fft, field_0: fft(field_0)), Rule("field_0", lambda ifft, spec_0: ifft(spec_0)), - Rule("spec_0", utils.load_previous_spectrum, ["recovery_data_dir"], priorities=4), - Rule("spec_0", utils.load_previous_spectrum, priorities=3), *Rule.deduce( ["pre_field_0", "peak_power", "energy", "width"], pulse.adjust_custom_field, @@ -355,7 +353,7 @@ default_rules: list[Rule] = [ Rule( "n_eff", fiber.n_eff_pcf, - ["wl_for_disp", "pitch", "pitch_ratio"], + ["wl_for_disp", "pcf_pitch", "pcf_pitch_ratio"], conditions=dict(model="pcf"), ), Rule("n0", lambda w0_ind, n_eff: n_eff[w0_ind]), @@ -370,18 +368,17 @@ default_rules: list[Rule] = [ lambda beta2_arr, wl_for_disp: wl_for_disp[math.argclosest(beta2_arr, 0)], ), # 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", fiber.A_eff_marcatili, priorities=-2), - 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("effective_area", fiber.effective_area_from_V), + Rule("effective_area", fiber.effective_area_from_diam), + Rule("effective_area", fiber.effective_area_hasan, conditions=dict(model="hasan")), + Rule("effective_area", fiber.effective_area_from_gamma, priorities=-1), + Rule("effective_area", fiber.elfective_area_marcatili, priorities=-2), + Rule("effecive_area_arr", fiber.effective_area_from_V, ["core_radius", "V_eff_arr"]), + Rule("effecive_area_arr", fiber.load_custom_effective_area), Rule( "V_eff", fiber.V_parameter_koshiba, - ["wavelength", "pitch", "pitch_ratio"], + ["wavelength", "pcf_pitch", "pcf_pitch_ratio"], conditions=dict(model="pcf"), ), Rule( @@ -399,7 +396,7 @@ default_rules: list[Rule] = [ Rule("n2", lambda: 2.2e-20, priorities=-1), Rule("gamma", lambda gamma_arr: gamma_arr[0], priorities=-1), Rule("gamma", fiber.gamma_parameter), - Rule("gamma_arr", fiber.gamma_parameter, ["n2", "w0", "A_eff_arr"]), + Rule("gamma_arr", fiber.gamma_parameter, ["n2", "w0", "effecive_area_arr"]), # Raman Rule(["hr_w", "raman_fraction"], fiber.delayed_raman_w), Rule("raman_fraction", fiber.raman_fraction), diff --git a/src/scgenerator/operators.py b/src/scgenerator/operators.py index 08af32f..9b2ac4e 100755 --- a/src/scgenerator/operators.py +++ b/src/scgenerator/operators.py @@ -315,11 +315,13 @@ def full_field_spm(raman_fraction: float, w: np.ndarray, chi3: float) -> FieldOp ################################################## -def variable_gamma(n2_op: VariableQuantity, w0: float, A_eff: float, t_num: int) -> SpecOperator: +def variable_gamma( + n2_op: VariableQuantity, w0: float, effective_area: float, t_num: int +) -> SpecOperator: arr = np.ones(t_num) def operate(z: float) -> np.ndarray: - return arr * fiber.gamma_parameter(n2_op(z), w0, A_eff) + return arr * fiber.gamma_parameter(n2_op(z), w0, effective_area) return operate diff --git a/src/scgenerator/parameter.py b/src/scgenerator/parameter.py index 0d69f55..0475085 100644 --- a/src/scgenerator/parameter.py +++ b/src/scgenerator/parameter.py @@ -7,8 +7,7 @@ from dataclasses import dataclass, field, fields from functools import lru_cache, wraps from math import isnan from pathlib import Path -from typing import (Any, Callable, ClassVar, Iterable, Iterator, Set, Type, - TypeVar) +from typing import Any, Callable, ClassVar, Iterable, Iterator, Set, Type, TypeVar import numpy as np @@ -229,7 +228,7 @@ class Parameter: when displaying the value example : (1e-6, "MW") will mean the value 1.12e6 is displayed as '1.12MW' """ - self.__validator = validator + self._validator = validator self.converter = converter self.default = default self.display_info = display_info @@ -247,28 +246,25 @@ class Parameter: def __get__(self, instance: Parameters, owner): if instance is None: return self - if self.name not in instance._param_dico: - try: - instance._evaluator.compute(self.name) - except EvaluatorError: - pass return instance._param_dico.get(self.name) - # return instance.__dict__[self.name] def __delete__(self, instance): - raise AttributeError("Cannot delete parameter") + if self.name in instance._param_dico: + del instance._param_dico[self.name] def __set__(self, instance: Parameters, value): - if isinstance(value, Parameter): - if self.default is not None: - instance._param_dico[self.name] = copy(self.default) + if instance._frozen: + raise AttributeError("Parameters instance is frozen and can no longer be modified") + + if isinstance(value, Parameter) and self.default is not None: + instance._param_dico[self.name] = copy(self.default) + return + + is_value, value = self.validate(value) + if is_value: + instance._param_dico[self.name] = value else: - is_value, value = self.validate(value) - if is_value: - instance._param_dico[self.name] = value - else: - if self.name in instance._param_dico: - del instance._param_dico[self.name] + self.__delete__(instance) def display(self, num: float) -> str: if self.display_info is None: @@ -291,12 +287,9 @@ class Parameter: if is_value: if self.converter is not None: v = self.converter(v) - self.__validator(self.name, v) + self._validator(self.name, v) return is_value, v - def validator(self, name, value): - self.validate(value) - @dataclass(repr=False) class Parameters: @@ -308,11 +301,10 @@ class Parameters: _param_dico: dict[str, Any] = field(init=False, default_factory=dict, repr=False) _evaluator: Evaluator = field(init=False, repr=False) _p_names: ClassVar[Set[str]] = set() + _frozen: bool = field(init=False, default=False, repr=False) # root name: str = Parameter(string, default="no name") - prev_data_dir: str = Parameter(string) - recovery_data_dir: str = Parameter(string) output_path: Path = Parameter(type_checker(Path), default=Path("sc_data"), converter=Path) # fiber @@ -323,11 +315,11 @@ class Parameters: loss: str = Parameter(literal("capillary")) loss_file: str = Parameter(string) effective_mode_diameter: float = Parameter(positive(float, int)) - A_eff: float = Parameter(non_negative(float, int)) - A_eff_file: str = Parameter(string) + effective_area: float = Parameter(non_negative(float, int)) + effective_area_file: str = Parameter(string) numerical_aperture: float = Parameter(in_range_excl(0, 1)) - pitch: float = Parameter(in_range_excl(0, 1e-3), display_info=(1e6, "μm")) - pitch_ratio: float = Parameter(in_range_excl(0, 1)) + pcf_pitch: float = Parameter(in_range_excl(0, 1e-3), display_info=(1e6, "μm")) + pcf_pitch_ratio: float = Parameter(in_range_excl(0, 1)) core_radius: float = Parameter(in_range_excl(0, 1e-3), display_info=(1e6, "μm")) he_mode: tuple[int, int] = Parameter(int_pair, default=(1, 1)) fit_parameters: tuple[int, int] = Parameter(float_pair, default=(0.08, 200e-9)) @@ -421,7 +413,7 @@ class Parameters: alpha_arr: np.ndarray = Parameter(type_checker(np.ndarray)) alpha: float = Parameter(non_negative(float, int)) gamma_arr: np.ndarray = Parameter(type_checker(np.ndarray)) - A_eff_arr: np.ndarray = Parameter(type_checker(np.ndarray)) + effective_area_arr: np.ndarray = Parameter(type_checker(np.ndarray)) spectrum_factor: float = Parameter(type_checker(float)) c_to_a_factor: np.ndarray = Parameter(type_checker(float, int, np.ndarray)) w: np.ndarray = Parameter(type_checker(np.ndarray)) @@ -524,7 +516,7 @@ class Parameters: "wl_for_disp", "alpha", "gamma_arr", - "A_eff_arr", + "effective_area_arr", "nonlinear_op", "linear_op", } diff --git a/src/scgenerator/physics/fiber.py b/src/scgenerator/physics/fiber.py index 04a90c1..cead06b 100644 --- a/src/scgenerator/physics/fiber.py +++ b/src/scgenerator/physics/fiber.py @@ -205,7 +205,7 @@ def n_eff_marcatili_adjusted(wl_for_disp, n_gas_2, core_radius, he_mode=(1, 1), return np.sqrt(n_gas_2 - (wl_for_disp * u / (pipi * corrected_radius)) ** 2) -def A_eff_marcatili(core_radius: float) -> float: +def effective_area_marcatili(core_radius: float) -> float: """Effective mode-field area for fundamental mode hollow capillaries Parameters @@ -353,7 +353,7 @@ def n_eff_hasan( return np.sqrt(n_eff_2) -def A_eff_hasan(core_radius, capillary_num, capillary_spacing): +def effective_area_hasan(core_radius, capillary_num, capillary_spacing): """computed the effective mode area Parameters @@ -367,7 +367,7 @@ def A_eff_hasan(core_radius, capillary_num, capillary_spacing): Returns ------- - A_eff : float + effective_area: float """ M_f = 1.5 / (1 - 0.5 * np.exp(-0.245 * capillary_num)) return M_f * core_radius**2 * np.exp((capillary_spacing / 22e-6) ** 2.5) @@ -405,7 +405,7 @@ def V_eff_step_index( return pi2cn / l -def V_parameter_koshiba(l: np.ndarray, pitch: float, pitch_ratio: float) -> float: +def V_parameter_koshiba(l: np.ndarray, pcf_pitch: float, pcf_pitch_ratio: float) -> float: """returns the V parameter according to Koshiba2004 @@ -413,9 +413,9 @@ def V_parameter_koshiba(l: np.ndarray, pitch: float, pitch_ratio: float) -> floa ---------- l : np.ndarray, shape (n,) wavelength - pitch : float + pcf_pitch : float distance between air holes in m - pitch_ratio : float + pcf_pitch_ratio : float ratio diameter of holes / distance w0 : float pump angular frequency @@ -425,11 +425,11 @@ def V_parameter_koshiba(l: np.ndarray, pitch: float, pitch_ratio: float) -> floa float effective mode field area """ - ratio_l = l / pitch + ratio_l = l / pcf_pitch n_co = 1.45 - a_eff = pitch / np.sqrt(3) + a_eff = pcf_pitch / np.sqrt(3) pi2a = pipi * a_eff - A, B = saitoh_paramters(pitch_ratio) + A, B = saitoh_paramters(pcf_pitch_ratio) V = A[0] + A[1] / (1 + A[2] * np.exp(A[3] * ratio_l)) @@ -439,7 +439,7 @@ def V_parameter_koshiba(l: np.ndarray, pitch: float, pitch_ratio: float) -> floa return V_eff -def A_eff_from_V(core_radius: float, V_eff: T) -> T: +def effective_area_from_V(core_radius: float, V_eff: T) -> T: """According to Marcuse1978 Parameters @@ -452,7 +452,8 @@ def A_eff_from_V(core_radius: float, V_eff: T) -> T: Returns ------- T - A_eff + effective_area + """ out = np.ones_like(V_eff) out[V_eff > 0] = core_radius * ( @@ -533,20 +534,21 @@ def HCPCF_dispersion( return beta2(w, n_eff) -def gamma_parameter(n2: float, w0: float, A_eff: T) -> T: - if isinstance(A_eff, np.ndarray): - A_eff_term = np.sqrt(A_eff * A_eff[0]) +def gamma_parameter(n2: float, w0: float, effective_area: T) -> T: + if isinstance(effective_area, np.ndarray): + effective_area_term = np.sqrt(effective_area * effective_area[0]) else: - A_eff_term = A_eff - return n2 * w0 / (A_eff_term * c) + effective_area_term = effective_area + + return n2 * w0 / (effective_area_term * c) -def constant_A_eff_arr(l: np.ndarray, A_eff: float) -> np.ndarray: - return np.ones_like(l) * A_eff +def constant_effective_area_arr(l: np.ndarray, effective_area: float) -> np.ndarray: + return np.ones_like(l) * effective_area @np_cache -def n_eff_pcf(wl_for_disp: np.ndarray, pitch: float, pitch_ratio: float) -> np.ndarray: +def n_eff_pcf(wl_for_disp: np.ndarray, pcf_pitch: float, pcf_pitch_ratio: float) -> np.ndarray: """ semi-analytical computation of the dispersion profile of a triangular Index-guiding PCF @@ -554,10 +556,10 @@ def n_eff_pcf(wl_for_disp: np.ndarray, pitch: float, pitch_ratio: float) -> np.n ---------- wl_for_disp : np.ndarray, shape (n,) wavelengths over which to calculate the dispersion - pitch : float + pcf_pitch : float distance between air holes in m - pitch_ratio : float - ratio diameter of hole / pitch + pcf_pitch_ratio : float + ratio diameter of hole / pcf_pitch Returns ------- @@ -570,15 +572,15 @@ def n_eff_pcf(wl_for_disp: np.ndarray, pitch: float, pitch_ratio: float) -> np.n """ # Check validity - 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") + if pcf_pitch_ratio < 0.2 or pcf_pitch_ratio > 0.8: + print("WARNING : Fitted formula valid only for pcf_pitch ratio between 0.2 and 0.8") - a_eff = pitch / np.sqrt(3) - pi2a = pipi * a_eff + effective_area = pcf_pitch / np.sqrt(3) + pi2a = pipi * effective_area - ratio_l = wl_for_disp / pitch + ratio_l = wl_for_disp / pcf_pitch - A, B = saitoh_paramters(pitch_ratio) + A, B = saitoh_paramters(pcf_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)) @@ -591,15 +593,15 @@ def n_eff_pcf(wl_for_disp: np.ndarray, pitch: float, pitch_ratio: float) -> np.n return n_eff + np.sqrt(chi_mat + 1) -def A_eff_from_diam(effective_mode_diameter: float) -> float: +def effective_area_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): +def effective_area_from_gamma(gamma: float, n2: float, w0: float): return n2 * w0 / (c * gamma) -def saitoh_paramters(pitch_ratio: float) -> tuple[float, float]: +def saitoh_paramters(pcf_pitch_ratio: float) -> tuple[float, float]: # Table 1 and 2 in Saitoh2005 ai0 = np.array([0.54808, 0.71041, 0.16904, -1.52736]) ai1 = np.array([5.00401, 9.73491, 1.85765, 1.06745]) @@ -616,17 +618,27 @@ def saitoh_paramters(pitch_ratio: float) -> tuple[float, float]: di2 = np.array([9, 6.58, 10, 0.41]) di3 = np.array([10, 24.8, 15, 6]) - A = ai0 + ai1 * pitch_ratio**bi1 + ai2 * pitch_ratio**bi2 + ai3 * pitch_ratio**bi3 - B = ci0 + ci1 * pitch_ratio**di1 + ci2 * pitch_ratio**di2 + ci3 * pitch_ratio**di3 + A = ( + ai0 + + ai1 * pcf_pitch_ratio**bi1 + + ai2 * pcf_pitch_ratio**bi2 + + ai3 * pcf_pitch_ratio**bi3 + ) + B = ( + ci0 + + ci1 * pcf_pitch_ratio**di1 + + ci2 * pcf_pitch_ratio**di2 + + ci3 * pcf_pitch_ratio**di3 + ) return A, B -def load_custom_A_eff(A_eff_file: str, l: np.ndarray) -> np.ndarray: +def load_custom_effective_area(effective_area_file: str, l: np.ndarray) -> np.ndarray: """loads custom effective area file Parameters ---------- - A_eff_file : str + effective_area_file : str relative or absolute path to the file l : np.ndarray, shape (n,) wavelength array of the simulation @@ -636,10 +648,10 @@ def load_custom_A_eff(A_eff_file: str, l: np.ndarray) -> np.ndarray: np.ndarray, shape (n,) wl-dependent effective mode field area """ - data = np.load(A_eff_file) - A_eff = data["A_eff"] + data = np.load(effective_area_file) + effective_area = data.get("A_eff", data.get("effective_area")) wl = data["wavelength"] - return interp1d(wl, A_eff, fill_value=1, bounds_error=False)(l) + return interp1d(wl, effective_area, fill_value=1, bounds_error=False)(l) def load_custom_dispersion(dispersion_file: str) -> tuple[np.ndarray, np.ndarray]: diff --git a/src/scgenerator/physics/pulse.py b/src/scgenerator/physics/pulse.py index 2d702b0..5ab8c38 100644 --- a/src/scgenerator/physics/pulse.py +++ b/src/scgenerator/physics/pulse.py @@ -95,7 +95,13 @@ class PulseProperties: def initial_full_field( - t: np.ndarray, shape: str, A_eff: float, t0: float, peak_power: float, w0: float, n0: float + t: np.ndarray, + shape: str, + effective_area: float, + t0: float, + peak_power: float, + w0: float, + n0: float, ) -> np.ndarray: """initial field in full field simulations @@ -120,7 +126,9 @@ def initial_full_field( initial field """ return ( - initial_field_envelope(t, shape, t0, peak_power) * np.cos(w0 * t) * units.W_to_Vm(n0, A_eff) + initial_field_envelope(t, shape, t0, peak_power) + * np.cos(w0 * t) + * units.W_to_Vm(n0, effective_area) ) @@ -192,7 +200,7 @@ def modify_field_ratio( return ratio -def convert_field_units(envelope: np.ndarray, n: np.ndarray, A_eff: float) -> np.ndarray: +def convert_field_units(envelope: np.ndarray, n: np.ndarray, effective_area: float) -> np.ndarray: """[summary] Parameters @@ -201,7 +209,7 @@ def convert_field_units(envelope: np.ndarray, n: np.ndarray, A_eff: float) -> np complex envelope in units such that |envelope|^2 is in W n : np.ndarray, shape (n,) refractive index - A_eff : float + effective_area : float effective mode field area in m^2 Returns @@ -209,15 +217,15 @@ def convert_field_units(envelope: np.ndarray, n: np.ndarray, A_eff: float) -> np np.ndarray, shape (n,) real field in V/m """ - return 2 * envelope.real / np.sqrt(2 * units.epsilon0 * units.c * n * A_eff) + return 2 * envelope.real / np.sqrt(2 * units.epsilon0 * units.c * n * effective_area) -def c_to_a_factor(A_eff_arr: np.ndarray) -> np.ndarray: - return (A_eff_arr / A_eff_arr[0]) ** (1 / 4) +def c_to_a_factor(effective_area_arr: np.ndarray) -> np.ndarray: + return (effective_area_arr / effective_area_arr[0]) ** (1 / 4) -def a_to_c_factor(A_eff_arr: np.ndarray) -> np.ndarray: - return (A_eff_arr / A_eff_arr[0]) ** (-1 / 4) +def a_to_c_factor(effective_area_arr: np.ndarray) -> np.ndarray: + return (effective_area_arr / effective_area_arr[0]) ** (-1 / 4) def spectrum_factor_envelope(dt: float) -> float: @@ -510,12 +518,12 @@ def finalize_pulse( return np.sqrt(input_transmission) * pre_field_0 * ratio -def A_to_C(A: np.ndarray, A_eff_arr: np.ndarray) -> np.ndarray: - return (A_eff_arr / A_eff_arr[0]) ** (-1 / 4) * A +def A_to_C(A: np.ndarray, effective_area_arr: np.ndarray) -> np.ndarray: + return (effective_area_arr / effective_area_arr[0]) ** (-1 / 4) * A -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 +def C_to_A(C: np.ndarray, effective_area_arr: np.ndarray) -> np.ndarray: + return (effective_area_arr / effective_area_arr[0]) ** (1 / 4) * C def mean_phase(spectra): diff --git a/src/scgenerator/physics/units.py b/src/scgenerator/physics/units.py index 28aec79..5180339 100644 --- a/src/scgenerator/physics/units.py +++ b/src/scgenerator/physics/units.py @@ -10,7 +10,6 @@ from typing import Callable, TypeVar, Union import numpy as np from numpy import pi - c = 299792458.0 hbar = 1.05457148e-34 NA = 6.02214076e23 @@ -77,7 +76,7 @@ class To: raise KeyError(f"no registered unit named {key!r}") from None -def W_to_Vm(n0: float, A_eff: float) -> float: +def W_to_Vm(n0: float, effective_area: float) -> float: """returns the factor to convert from [|E|²] = W to [|E|] = V/m Parameters @@ -90,7 +89,7 @@ def W_to_Vm(n0: float, A_eff: float) -> float: float p such that E_sqrt(W) * p = W_Vm """ - return 1.0 / np.sqrt(A_eff * 0.5 * epsilon0 * c * n0) + return 1.0 / np.sqrt(effective_area * 0.5 * epsilon0 * c * n0) class unit: