replaced material_dico with Gas object

This commit is contained in:
Benoît Sierro
2023-01-24 11:22:53 +01:00
parent 239eaddd7c
commit 1baef68656
24 changed files with 212 additions and 613 deletions

View File

@@ -1,10 +1,11 @@
# flake8: noqa
from scgenerator import math, operators
from scgenerator.evaluator import Evaluator
from scgenerator.helpers import *
from scgenerator.legacy import convert_sim_folder
from scgenerator.math import abs2, argclosest, normalized, span, tspace, wspace
from scgenerator.parameter import FileConfiguration, Parameters
from scgenerator.physics import fiber, materials, pulse, simulate, units, plasma
from scgenerator.physics import fiber, materials, plasma, pulse, simulate, units
from scgenerator.physics.simulate import RK4IP, parallel_RK4IP, run_simulation
from scgenerator.physics.units import PlotRange
from scgenerator.plotting import (
@@ -25,4 +26,3 @@ from scgenerator.variationer import (
Variationer,
VariationSpecsError,
)
from scgenerator.helpers import *

View File

@@ -1,6 +1,7 @@
from collections import namedtuple
from copy import copy
from functools import wraps
import numpy as np
CacheInfo = namedtuple("CacheInfo", "hits misses size")

View File

@@ -1,7 +1,7 @@
__version__ = "0.2.6dev"
from typing import Any
__version__ = "0.2.7dev"
ONE_2 = 1 / 2
ONE_3 = 1 / 3
ONE_FOURTH = 1 / 4

View File

@@ -1,6 +1,6 @@
import matplotlib.pyplot as plt
from pathlib import Path
import matplotlib.pyplot as plt
default_plotting = dict(
figsize=(10, 7),

View File

@@ -2,7 +2,6 @@ import os
from pathlib import Path
from typing import Any, Dict, Literal, Optional, Set
ENVIRON_KEY_BASE = "SCGENERATOR_"
TMP_FOLDER_KEY_BASE = ENVIRON_KEY_BASE + "SC_TMP_"
PREFIX_KEY_BASE = ENVIRON_KEY_BASE + "PREFIX_"

View File

@@ -5,12 +5,11 @@ from typing import Any, Callable, Optional, Union
import numpy as np
from . import math, operators, utils
from .const import MANDATORY_PARAMETERS
from .errors import EvaluatorError, NoDefaultError
from .physics import fiber, materials, pulse, units
from .utils import _mock_function, func_rewrite, get_arg_names, get_logger
from scgenerator import math, operators, utils
from scgenerator.const import MANDATORY_PARAMETERS
from scgenerator.errors import EvaluatorError, NoDefaultError
from scgenerator.physics import fiber, materials, pulse, units
from scgenerator.utils import _mock_function, func_rewrite, get_arg_names, get_logger
class Rule:
@@ -336,7 +335,7 @@ default_rules: list[Rule] = [
# Fiber Dispersion
Rule("w_for_disp", units.m, ["wl_for_disp"]),
Rule("hr_w", fiber.delayed_raman_w),
Rule("gas_info", materials.GasInfo),
Rule("gas_info", materials.Gas),
Rule("chi_gas", lambda gas_info, wl_for_disp: gas_info.sellmeier.chi(wl_for_disp)),
Rule("n_gas_2", materials.n_gas_2),
Rule("n_eff", fiber.n_eff_hasan, conditions=dict(model="hasan")),

View File

@@ -5,7 +5,7 @@ series of helper functions
import numpy as np
from scgenerator.math import all_zeros
from scgenerator.physics.fiber import beta2, n_eff_marcatili, n_eff_hasan
from scgenerator.physics.fiber import beta2, n_eff_hasan, n_eff_marcatili
from scgenerator.physics.materials import n_gas_2
from scgenerator.physics.units import c
@@ -40,7 +40,7 @@ def capillary_dispersion(
pressure = 101325
if temperature is None:
temperature = 293.15
n = n_eff_marcatili(wl, n_gas_2(wl, gas_name.lower(), pressure, temperature, False), radius)
n = n_eff_marcatili(wl, n_gas_2(wl, gas_name.lower(), pressure, temperature), radius)
w = 2 * np.pi * c / wl
return beta2(w, n)[2:-2]
@@ -117,7 +117,7 @@ def revolver_dispersion(
temperature = 293.15
n = n_eff_hasan(
wl,
n_gas_2(wl, gas_name.lower(), pressure, temperature, False),
n_gas_2(wl, gas_name.lower(), pressure, temperature),
core_radius,
capillary_num,
capillary_nested,

View File

@@ -8,11 +8,11 @@ import numpy as np
import tomli
import tomli_w
from .const import SPEC1_FN, SPEC1_FN_N, SPECN_FN1
from .parameter import FileConfiguration, Parameters
from .pbar import PBars
from .utils import save_parameters
from .variationer import VariationDescriptor
from scgenerator.const import SPEC1_FN, SPEC1_FN_N, SPECN_FN1
from scgenerator.parameter import FileConfiguration, Parameters
from scgenerator.pbar import PBars
from scgenerator.utils import save_parameters
from scgenerator.variationer import VariationDescriptor
def load_config(path: os.PathLike) -> dict[str, Any]:

View File

@@ -1,6 +1,6 @@
import logging
from .env import log_file_level, log_print_level
from scgenerator.env import log_file_level, log_print_level
lvl_map: dict[str, int] = dict(

View File

@@ -7,7 +7,7 @@ from scipy.interpolate import interp1d, lagrange
from scipy.special import jn_zeros
from functools import cache
from .cache import np_cache
from scgenerator.cache import np_cache
pi = np.pi
c = 299792458.0

View File

@@ -6,15 +6,14 @@ from __future__ import annotations
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Any, Callable
from typing import Callable
import numpy as np
from scipy.interpolate import interp1d
from . import math
from .logger import get_logger
from .physics import fiber, materials, pulse, units, plasma
from .utils import load_material_dico
from scgenerator import math
from scgenerator.logger import get_logger
from scgenerator.physics import fiber, materials, plasma, pulse, units
class CurrentState:
@@ -212,8 +211,7 @@ class NoOpFreq(Operator):
class AbstractGas(Operator):
gas_name: str
material_dico: dict[str, Any]
gas: materials.Gas
def __call__(self, state: CurrentState) -> np.ndarray:
return self.square_index(state)
@@ -274,18 +272,10 @@ class ConstantGas(AbstractGas):
ideal_gas: bool,
wl_for_disp: np.ndarray,
):
self.material_dico = load_material_dico(gas_name)
self.gas_name = gas_name
self.gas = materials.Gas(gas_name)
self.pressure_const = pressure
if ideal_gas:
self.number_density_const = materials.number_density_van_der_waals(
pressure=pressure, temperature=temperature, material_dico=self.material_dico
)
else:
self.number_density_const = self.pressure_const / (units.kB * temperature)
self.n_gas_2_const = materials.n_gas_2(
wl_for_disp, gas_name, self.pressure_const, temperature, ideal_gas
)
self.number_density_const = self.gas.number_density(temperature, pressure, ideal_gas)
self.n_gas_2_const = self.gas.sellmeier.n_gas_2(wl_for_disp, temperature, pressure)
def pressure(self, state: CurrentState = None) -> float:
return self.pressure_const
@@ -311,10 +301,9 @@ class PressureGradientGas(AbstractGas):
ideal_gas: bool,
wl_for_disp: np.ndarray,
):
self.gas_name = gas_name
self.p_in = pressure_in
self.p_out = pressure_out
self.material_dico = load_material_dico(gas_name)
self.gas = materials.Gas(gas_name)
self.temperature = temperature
self.ideal_gas = ideal_gas
self.wl_for_disp = wl_for_disp
@@ -323,23 +312,10 @@ class PressureGradientGas(AbstractGas):
return materials.pressure_from_gradient(state.z_ratio, self.p_in, self.p_out)
def number_density(self, state: CurrentState) -> float:
if self.ideal_gas:
return self.pressure(state) / (units.kB * self.temperature)
else:
return materials.number_density_van_der_waals(
pressure=self.pressure(state),
temperature=self.temperature,
material_dico=self.material_dico,
)
return self.gas.number_density(self.temperature, self.pressure(state), self.ideal_gas)
def square_index(self, state: CurrentState) -> np.ndarray:
return materials.fast_n_gas_2(
self.wl_for_disp,
self.pressure(state),
self.temperature,
self.ideal_gas,
self.material_dico,
)
return self.gas.sellmeier.n_gas_2(self.wl_for_disp, self.temperature, self.pressure(state))
##################################################
@@ -829,9 +805,7 @@ class VariableScalarGamma(AbstractGamma):
self.arr = np.ones(t_num)
def __call__(self, state: CurrentState) -> np.ndarray:
n2 = materials.non_linear_refractive_index(
self.gas_op.material_dico, self.gas_op.pressure(state), self.temperature
)
n2 = self.gas_op.gas.n2(self.temperature, self.gas_op.pressure(state))
return self.arr * fiber.gamma_parameter(n2, self.w0, self.A_eff)
@@ -847,7 +821,7 @@ class Plasma(Operator):
def __init__(self, dt: float, w: np.ndarray, gas_op: AbstractGas):
self.gas_op = gas_op
self.mat_plasma = plasma.Plasma(dt, self.gas_op.material_dico["ionization_energy"])
self.mat_plasma = plasma.Plasma(dt, self.gas_op.gas["ionization_energy"])
self.factor_out = -w / (2.0 * units.c**2 * units.epsilon0)
def __call__(self, state: CurrentState) -> np.ndarray:

View File

@@ -9,19 +9,19 @@ 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, Union
from typing import Any, Callable, ClassVar, Iterable, Iterator, Set, Type, TypeVar
import numpy as np
from . import env, legacy, utils
from .const import MANDATORY_PARAMETERS, PARAM_FN, VALID_VARIABLE, __version__
from .errors import EvaluatorError
from .evaluator import Evaluator
from .logger import get_logger
from .operators import AbstractConservedQuantity, LinearOperator, NonLinearOperator
from .solver import Integrator
from .utils import DebugDict, fiber_folder, update_path_name
from .variationer import VariationDescriptor, Variationer
from scgenerator import env, legacy, utils
from scgenerator.const import MANDATORY_PARAMETERS, PARAM_FN, VALID_VARIABLE, __version__
from scgenerator.errors import EvaluatorError
from scgenerator.evaluator import Evaluator
from scgenerator.logger import get_logger
from scgenerator.operators import AbstractConservedQuantity, LinearOperator, NonLinearOperator
from scgenerator.solver import Integrator
from scgenerator.utils import DebugDict, fiber_folder, update_path_name
from scgenerator.variationer import VariationDescriptor, Variationer
T = TypeVar("T")

View File

@@ -10,7 +10,7 @@ from typing import Iterable, Union
from tqdm import tqdm
from .env import pbar_policy
from scgenerator.env import pbar_policy
T_ = typing.TypeVar("T_")

View File

@@ -8,10 +8,9 @@ from typing import TypeVar
import numpy as np
from scipy.optimize import minimize_scalar
from .. import math
from . import fiber, materials, units, pulse
from ..cache import np_cache
from ..utils import load_material_dico
from scgenerator import math
from scgenerator.cache import np_cache
from scgenerator.physics import fiber, materials, pulse, units
T = TypeVar("T")
@@ -28,8 +27,6 @@ def material_dispersion(
material: str,
pressure=None,
temperature=None,
ideal=True,
safe=True,
):
"""returns the dispersion profile (beta_2) of a bulk material.
@@ -54,23 +51,8 @@ def material_dispersion(
w = units.m(wavelengths)
if safe:
disp = np.zeros(len(w))
ind = w > 0
disp[ind] = material_dispersion(
units.m.inv(w[ind]), material, pressure, temperature, ideal, False
)
return disp
else:
material_dico = load_material_dico(material)
if ideal:
n_gas_2 = materials.sellmeier(wavelengths, material_dico, pressure, temperature) + 1
else:
N_1 = materials.number_density_van_der_waals(
pressure=pressure, temperature=temperature, material_dico=material_dico
)
N_0 = materials.number_density_van_der_waals(material_dico=material_dico)
n_gas_2 = materials.sellmeier(wavelengths, material_dico) * N_1 / N_0 + 1
sellmeier = materials.Sellmeier.load(material)
n_gas_2 = sellmeier.n_gas_2(wavelengths, temperature, pressure)
order = np.argsort(w)
unorder = np.argsort(order)
return fiber.beta2(w[order], np.sqrt(n_gas_2[order]))[unorder]
@@ -118,7 +100,7 @@ def find_optimal_depth(
def propagate_field(
t: np.ndarray, field: np.ndarray, z: float, material: str, center_wl_nm: float = 1540.0
t: np.ndarray, field: np.ndarray, z: float, material: str, center_wl_nm: float
) -> np.ndarray:
"""propagates a field through bulk material
@@ -132,8 +114,8 @@ def propagate_field(
distance to propagate in m
material : str
material name
center_wl_nm : float, optional
center wavelength of the grid in nm, by default 1540
center_wl_nm : float
center wavelength of the grid in nm
Returns
-------

View File

@@ -1,16 +1,17 @@
from typing import Any, Iterable, Literal, TypeVar
from typing import Iterable, TypeVar
import numpy as np
from numpy import e
from numpy.fft import fft
from numpy.polynomial.chebyshev import Chebyshev, cheb2poly
from scipy.interpolate import interp1d
from scgenerator import utils
from scgenerator.cache import np_cache
from scgenerator.math import argclosest, u_nm
from scgenerator.physics import materials as mat
from scgenerator.physics import units
from scgenerator.physics.units import c, pi
from scipy.interpolate import interp1d
pipi = 2 * pi
T = TypeVar("T")
@@ -255,7 +256,7 @@ def resonance_thickness(
float
thickness in m
"""
n_si_2 = mat.n_gas_2(wl_for_disp, "silica", None, None, True)
n_si_2 = mat.n_gas_2(wl_for_disp, "silica", None, None)
return (
wl_for_disp
/ (4 * np.sqrt(n_si_2))
@@ -268,7 +269,7 @@ def resonance_strength(
wl_for_disp: np.ndarray, core_radius: float, capillary_thickness: float, order: int
) -> float:
a = 1.83 + (2.3 * capillary_thickness / core_radius)
n_si = np.sqrt(mat.n_gas_2(wl_for_disp, "silica", None, None, True))
n_si = np.sqrt(mat.n_gas_2(wl_for_disp, "silica", None, None))
return (
capillary_thickness
/ (n_si * core_radius) ** (2.303 * a / n_si)
@@ -345,7 +346,7 @@ def n_eff_hasan(
n_eff_2 = n_gas_2 - (u * wl_for_disp / (pipi * R_eff)) ** 2
chi_sil = mat.sellmeier(wl_for_disp, utils.load_material_dico("silica"))
chi_sil = mat.Sellmeier.load("silica").chi(wl_for_disp)
with np.errstate(divide="ignore", invalid="ignore"):
for m, strength in enumerate(capillary_resonance_strengths):
@@ -466,143 +467,6 @@ def A_eff_from_V(core_radius: float, V_eff: T) -> T:
return out
def HCPCF_find_with_given_ZDW(
variable: Literal["pressure", "temperature"],
target: float,
search_range: tuple[float, float],
material_dico: dict[str, Any],
model="marcatili",
model_params={},
pressure=None,
temperature=None,
ideal=False,
):
"""finds the parameters (pressure or temperature) to yield the target ZDW. assign the string value 'vary' to the parameter
Parameters
----------
variable : str {"pressure", "temperature"}
which parameter to vary
target : float
the ZDW target, in m
search_range : array, shape (2,)
(min, max) of the search range
other parameters : see HCPCF_dispersion. Pressure or temperature is used as initial value if it is variable
Returns
-------
the parameter that satisfies the ZDW
"""
from scipy import optimize
l_search = [120e-9, 6000e-9]
#
fixed = [material_dico, model, model_params, ideal]
if variable == "pressure":
fixed.append(temperature)
x0 = 1e5 if pressure is None else pressure
def zdw(x, *args):
current_ZDW = HCPF_ZDW(
l_search,
args[0],
model=args[1],
model_params=args[2],
pressure=x,
temperature=args[4],
ideal=args[3],
)
out = current_ZDW - target
return out
elif variable == "temperature":
fixed.append(pressure)
x0 = 273.15 if temperature is None else temperature
def zdw(x, *args):
current_ZDW = HCPF_ZDW(
l_search,
args[0],
model=args[1],
model_params=args[2],
pressure=args[4],
temperature=x,
ideal=args[3],
)
out = current_ZDW - target
return out
else:
raise AttributeError(f"'variable' arg must be 'pressure' or 'temperature', not {variable}")
optimized = optimize.root_scalar(
zdw, x0=x0, args=tuple(fixed), method="brentq", bracket=search_range
)
return optimized.root
def HCPF_ZDW(
search_range,
material_dico,
model="marcatili",
model_params={},
pressure=None,
temperature=None,
ideal=False,
max_iter=10,
threshold=1e-36,
):
"""finds one Zero Dispersion Wavelength (ZDW) of a given HC-PCF fiber
Parameters
----------
see HCPCF_dispersion for description of most arguments
max_iter : float
How many iterations are allowed at most to reach the threashold
threshold : float
upper bound of what counts as beta2 == 0 (in si units)
Returns
-------
float:
the ZDW in m
"""
prev_find = np.inf
l = np.linspace(*search_range, 50)
core_radius = model_params["core_radius"]
zdw_ind = 0
for i in range(max_iter):
beta2 = HCPCF_dispersion(
l,
material_dico,
model=model,
model_params=model_params,
pressure=pressure,
temperature=temperature,
ideal=ideal,
)
zdw_ind = argclosest(beta2, 0)
if beta2[zdw_ind] < threshold:
break
elif beta2[zdw_ind] < prev_find:
l = np.linspace(
l[zdw_ind] - (100 / (i + 1)) * 1e-9, l[zdw_ind] + (100 / (i + 1)) * 1e-9, 50
)
prev_find = beta2[zdw_ind]
else:
raise RuntimeError(
f"Could not find a ZDW with parameters {1e6*core_radius} um, {1e-5 * pressure} bar, {temperature} K."
)
else:
print(f"Could not get to threshold in {max_iter} iterations")
return l[zdw_ind]
def beta(w_for_disp: np.ndarray, n_eff: np.ndarray) -> np.ndarray:
return n_eff * w_for_disp / c
@@ -634,12 +498,11 @@ def frame_velocity(beta1_arr: np.ndarray, w0_ind: int) -> float:
def HCPCF_dispersion(
wl_for_disp,
material_dico=None,
gas_name: str,
model="marcatili",
model_params={},
pressure=None,
temperature=None,
ideal=False,
**model_params,
):
"""returns the dispersion profile (beta_2) of a hollow-core photonic crystal fiber.
@@ -647,8 +510,8 @@ def HCPCF_dispersion(
----------
wl_for_disp : ndarray, shape (n, )
wavelengths over which to calculate the dispersion
material_dico : dict
material dictionary respecting standard format explained in FIXME
gas_name : str
name of the filling gas in lower case
model : string {"marcatili", "marcatili_adjusted", "hasan"}
which model of effective refractive index to use
model_params : tuple
@@ -666,17 +529,7 @@ def HCPCF_dispersion(
"""
w = units.m(wl_for_disp)
if material_dico is None:
n_gas_2 = np.ones_like(wl_for_disp)
else:
if ideal:
n_gas_2 = mat.sellmeier(wl_for_disp, material_dico, pressure, temperature) + 1
else:
N_1 = mat.number_density_van_der_waals(
pressure=pressure, temperature=temperature, material_dico=material_dico
)
N_0 = mat.number_density_van_der_waals(material_dico=material_dico)
n_gas_2 = mat.sellmeier(wl_for_disp, material_dico) * N_1 / N_0 + 1
n_gas_2 = mat.Sellmeier.load(gas_name).n_gas_2(wl_for_disp, temperature, pressure)
n_eff_func = dict(
marcatili=n_eff_marcatili, marcatili_adjusted=n_eff_marcatili_adjusted, hasan=n_eff_hasan
@@ -686,81 +539,6 @@ def HCPCF_dispersion(
return beta2(w, n_eff)
def dynamic_HCPCF_dispersion(
wl_for_disp: np.ndarray,
pressure_values: list[float],
core_radius: float,
fiber_model: str,
model_params: dict[str, Any],
temperature: float,
ideal_gas: bool,
w0: float,
interp_range: tuple[float, float],
material_dico: dict[str, Any],
deg: int,
):
"""returns functions for beta2 coefficients and gamma instead of static values
Parameters
----------
wl_for_disp : wavelength array
params : dict
flattened parameter dictionary
material_dico : dict
material dictionary (see README for details)
Returns
-------
beta2_coef : func(r), r is the relative position in the fiber
a function that returns an array of coefficients as function of the relative position in the fiber
to be used in disp_op
gamma : func(r), r is the relative position in the fiber
a function that returns a float corresponding to the nonlinear parameter at the relative position
in the fiber
"""
A_eff = 1.5 * core_radius**2
# defining function instead of storing every possilble value
def pressure(r):
return mat.pressure_from_gradient(r, *pressure_values)
def beta2(r):
return HCPCF_dispersion(
wl_for_disp,
core_radius,
material_dico,
fiber_model,
model_params,
pressure(r),
temperature,
ideal_gas,
)
def n2(r):
return mat.non_linear_refractive_index(material_dico, pressure(r), temperature)
ratio_range = np.linspace(0, 1, 256)
gamma_grid = np.array([gamma_parameter(n2(r), w0, A_eff) for r in ratio_range])
gamma_interp = interp1d(ratio_range, gamma_grid)
beta2_grid = np.array(
[dispersion_coefficients(wl_for_disp, beta2(r), w0, interp_range, deg) for r in ratio_range]
)
beta2_interp = [
interp1d(ratio_range, beta2_grid[:, i], assume_sorted=True) for i in range(deg + 1)
]
def beta2_func(r):
return [beta2_interp[i](r)[()] for i in range(deg + 1)]
def gamma_func(r):
return gamma_interp(r)[()]
return beta2_func, gamma_func
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])
@@ -815,8 +593,7 @@ def n_eff_pcf(wl_for_disp: np.ndarray, pitch: float, pitch_ratio: float) -> np.n
n_eff2 = (wl_for_disp * W / (pi2a)) ** 2 + n_FSM2
n_eff = np.sqrt(n_eff2)
material_dico = utils.load_material_dico("silica")
chi_mat = mat.sellmeier(wl_for_disp, material_dico)
chi_mat = mat.Sellmeier.load("silica").chi(wl_for_disp)
return n_eff + np.sqrt(chi_mat + 1)
@@ -1121,7 +898,7 @@ def capillary_loss(wl: np.ndarray, he_mode: tuple[int, int], core_radius: float)
np.ndarray
loss in 1/m
"""
chi_silica = abs(mat.sellmeier(wl, utils.load_material_dico("silica")))
chi_silica = abs(mat.Sellmeier.load("silica").chi(wl))
nu_n = 0.5 * (chi_silica + 2) / np.sqrt(chi_silica)
return nu_n * (u_nm(*he_mode) * wl / pipi) ** 2 * core_radius**-3

View File

@@ -1,10 +1,11 @@
from __future__ import annotations
import functools
from dataclasses import dataclass, field
from typing import Any, TypeVar
from functools import cache
from typing import TypeVar
import numpy as np
from scgenerator import utils
from scgenerator.cache import np_cache
from scgenerator.logger import get_logger
@@ -24,6 +25,7 @@ class Sellmeier:
constant: float = 0
@classmethod
@cache
def load(cls, name: str) -> Sellmeier:
mat_dico = utils.load_material_dico(name)
s = mat_dico.get("sellmeier", {})
@@ -38,7 +40,7 @@ class Sellmeier:
}
)
def chi(self, wl: T) -> T:
def chi(self, wl: T, temperature: float | None = None, pressure: float | None = None) -> T:
"""n^2 - 1"""
if isinstance(wl, np.ndarray):
chi = np.zeros_like(wl) # = n^2 - 1
@@ -59,32 +61,32 @@ class Sellmeier:
else:
raise ValueError(f"kind {self.kind} is not recognized.")
# if temperature is not None:
# chi *= self.temperature_ref / temperature
if temperature is not None:
chi *= self.temperature_ref / temperature
# if pressure is not None:
# chi *= pressure / self.pressure_ref
if pressure is not None:
chi *= pressure / self.pressure_ref
return chi
def n_gas_2(self, wl: T) -> T:
return self.chi(wl) + 1
def n_gas_2(self, wl: T, temperature: float | None = None, pressure: float | None = None) -> T:
return self.chi(wl, temperature, pressure) + 1
def n(self, wl: T) -> T:
return np.sqrt(self.n_gas_2(wl))
def n(self, wl: T, temperature: float | None = None, pressure: float | None = None) -> T:
return np.sqrt(self.n_gas_2(wl, temperature, pressure))
class GasInfo:
class Gas:
name: str
sellmeier: Sellmeier
n2: float
atomic_number: int
atomic_mass: float
ionization_energy: float
_n2: float
ionization_energy: float | None
def __init__(self, gas_name: str):
self.name = gas_name
self.mat_dico = utils.load_material_dico(gas_name)
self.n2 = self.mat_dico["kerr"]["n2"]
self._n2 = self.mat_dico["kerr"]["n2"]
self.atomic_mass = self.mat_dico["atomic_mass"]
self.atomic_number = self.mat_dico["atomic_number"]
self.ionization_energy = self.mat_dico.get("ionization_energy")
@@ -130,11 +132,9 @@ class GasInfo:
/ temperature
)
else:
return number_density_van_der_waals(
self.get("a"), self.get("b"), pressure, temperature
) / number_density_van_der_waals(
self.get("a"),
self.get("b"),
return self.number_density_van_der_waals(
pressure, temperature
) / self.number_density_van_der_waals(
self.sellmeier.pressure_ref,
self.sellmeier.temperature_ref,
)
@@ -161,80 +161,22 @@ class GasInfo:
if ideal_gas:
return pressure / temperature / kB
else:
return number_density_van_der_waals(self.get("a"), self.get("b"), pressure, temperature)
return self.number_density_van_der_waals(pressure, temperature)
@property
def ionic_charge(self):
return self.atomic_number - 1
def get(self, key, default=None):
return self.mat_dico.get(key, default)
def __getitem__(self, key):
return self.mat_dico[key]
def __repr__(self) -> str:
return f"{self.__class__.__name__}({self.name!r})"
@np_cache
def n_gas_2(
wl_for_disp: np.ndarray, gas_name: str, pressure: float, temperature: float, ideal_gas: bool
):
"""Returns the sqare of the index of refraction of the specified gas"""
material_dico = utils.load_material_dico(gas_name)
n_gas_2 = fast_n_gas_2(wl_for_disp, pressure, temperature, ideal_gas, material_dico)
return n_gas_2
def fast_n_gas_2(
wl_for_disp: np.ndarray,
pressure: float,
temperature: float,
ideal_gas: bool,
material_dico: dict[str, Any],
):
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):
"""returns the pressure as function of distance with eq. 20 in Markos et al. (2017)
Parameters
----------
ratio : relative position in the fiber (0 = start, 1 = end)
p0 : pressure at the start
p1 : pressure at the end
Returns
----------
the pressure (float)
"""
return np.sqrt(p0**2 - ratio * (p0**2 - p1**2))
def number_density_van_der_waals(
a=None, b=None, pressure=None, temperature=None, material_dico=None
):
def number_density_van_der_waals(self, pressure: float = None, temperature: float = None):
"""returns the number density of a gas
Parameters
----------
P : pressure
T : temperature
for pressure and temperature, the default
a : Van der Waals a coefficient
b : Van der Waals b coefficient
material_dico : optional. If passed, will compute the number density at given reference values found in material_dico
pressure : float, optional
pressure in Pa, by default the reference pressure
temperature : float, optional
temperature in K, by default the reference temperature
Returns
----------
the numbers density (/m^3)
Raises
----------
ValueError : Since the Van der Waals equation is a cubic one, there could be more than one real, positive solution
@@ -244,19 +186,12 @@ def number_density_van_der_waals(
if pressure == 0:
return 0
if material_dico is not None:
a = material_dico.get("a", 0) if a is None else a
b = material_dico.get("b", 0) if b is None else b
pressure = material_dico["sellmeier"].get("P0", 101325) if pressure is None else pressure
a = self.mat_dico.get("a", 0)
b = self.mat_dico.get("b", 0)
pressure = self.mat_dico["sellmeier"].get("P0", 101325) if pressure is None else pressure
temperature = (
material_dico["sellmeier"].get("T0", 273.15) if temperature is None else temperature
self.mat_dico["sellmeier"].get("T0", 273.15) if temperature is None else temperature
)
else:
a = 0 if a is None else a
b = 0 if b is None else b
pressure = 101325 if pressure is None else pressure
temperature = 273.15 if temperature is None else temperature
ap = a / NA**2
bp = b / NA
@@ -277,133 +212,71 @@ def number_density_van_der_waals(
logger.warning(s)
return np.min(roots)
def n2(self, temperature: float | None = None, pressure: float | None = None) -> float:
"""nonlinear refractive index"""
@functools.singledispatch
def sellmeier(
wl_for_disp: np.ndarray,
material_dico: dict[str, Any],
pressure: float = None,
temperature: float = None,
) -> np.ndarray:
"""reads a file containing the Sellmeier values corresponding to the choses material and
returns the real susceptibility pressure and temperature adjustments are made according to
ideal gas law.
# if pressure and/or temperature are specified, adjustment is made according to number density ratio
if pressure is not None or temperature is not None:
N0 = self.number_density_van_der_waals()
N = self.number_density_van_der_waals(pressure, temperature)
ratio = N / N0
else:
ratio = 1
return ratio * self._n2
@property
def ionic_charge(self):
return self.atomic_number - 1
def get(self, key, default=None):
return self.mat_dico.get(key, default)
def __getitem__(self, key):
return self.mat_dico[key]
def __repr__(self) -> str:
return f"{self.__class__.__name__}({self.name!r})"
@np_cache
def n_gas_2(wl_for_disp: np.ndarray, gas_name: str, pressure: float, temperature: float):
"""Returns the sqare of the index of refraction of the specified gas"""
return Sellmeier.load(gas_name).n_gas_2(wl_for_disp, temperature, pressure)
def pressure_from_gradient(ratio, p0, p1):
"""returns the pressure as function of distance with eq. 20 in Markos et al. (2017)
Parameters
----------
wl_for_disp : array, shape (n,)
wavelength vector over which to compute the refractive index
material_dico : dict[str, Any]
material dictionary as explained in scgenerator.utils.load_material_dico
pressure : float, optional
pressure in Pa, by default None
temperature : float, optional
temperature of the gas in Kelvin
ratio : relative position in the fiber (0 = start, 1 = end)
p0 : pressure at the start
p1 : pressure at the end
Returns
-------
array, shape (n,)
chi = n^2 - 1
----------
the pressure (float)
"""
logger = get_logger(__name__)
WL_THRESHOLD = 8.285e-6
ind = wl_for_disp < WL_THRESHOLD
temp_l = wl_for_disp[ind]
B = material_dico["sellmeier"]["B"]
C = material_dico["sellmeier"]["C"]
const = material_dico["sellmeier"].get("const", 0)
P0 = material_dico["sellmeier"].get("P0", 1e5)
t0 = material_dico["sellmeier"].get("t0", 273.15)
kind = material_dico["sellmeier"].get("kind", 1)
chi = np.zeros_like(wl_for_disp) # = n^2 - 1
if kind == 1:
logger.debug("materials : using Sellmeier 1st kind equation")
for b, c_ in zip(B, C):
chi[ind] += temp_l**2 * b / (temp_l**2 - c_)
elif kind == 2: # gives n-1
logger.debug("materials : using Sellmeier 2nd kind equation")
for b, c_ in zip(B, C):
chi[ind] += b / (c_ - 1 / temp_l**2)
chi += const
chi = (chi + 1) ** 2 - 1
elif kind == 3: # Schott formula
logger.debug("materials : using Schott equation")
for i, b in reversed(list(enumerate(B))):
chi[ind] += b * temp_l ** (-2 * (i - 1))
chi[ind] = chi[ind] - 1
else:
raise ValueError(f"kind {kind} is not recognized.")
if temperature is not None:
chi *= t0 / temperature
if pressure is not None:
chi *= pressure / P0
logger.debug(f"computed chi between {np.min(chi):.2e} and {np.max(chi):.2e}")
return chi
return np.sqrt(p0**2 - ratio * (p0**2 - p1**2))
@sellmeier.register
def sellmeier_scalar(
wavelength: float,
material_dico: dict[str, Any],
pressure: float = None,
temperature: float = None,
) -> float:
"""n^2 - 1"""
return float(sellmeier(np.array([wavelength]), material_dico, pressure, temperature)[0])
def delta_gas(w, material_dico):
def delta_gas(w: np.ndarray, gas: Gas) -> np.ndarray:
"""returns the value delta_t (eq. 24 in Markos(2017))
Parameters
----------
w : angular frequency array
material_dico : material dictionary as explained in scgenerator.utils.load_material_dico
w : np.ndarray
angular frequency array
gas : Gas
Returns
----------
delta_t
since 2 gradients are computed, it is recommended to exclude the 2 extremum values
"""
chi = sellmeier(units.m.inv(w), material_dico)
N0 = number_density_van_der_waals(material_dico=material_dico)
chi = gas.sellmeier.chi(units.m.inv(w))
N0 = gas.number_density_van_der_waals()
dchi_dw = np.gradient(chi, w)
return 1 / (N0 * c) * (dchi_dw + w / 2 * np.gradient(dchi_dw, w))
def non_linear_refractive_index(material_dico, pressure=None, temperature=None):
"""returns the non linear refractive index n2 adjusted for pressure and temperature
NOTE : so far, there is no adjustment made for wavelength
Parameters
----------
lambda_ : wavelength array
material_dico :
pressure : pressure in Pa
temperature : temperature in Kelvin
Returns
----------
n2
"""
n2_ref = material_dico["kerr"]["n2"]
# if pressure and/or temperature are specified, adjustment is made according to number density ratio
if pressure is not None or temperature is not None:
N0 = number_density_van_der_waals(material_dico=material_dico)
N = number_density_van_der_waals(
pressure=pressure, temperature=temperature, material_dico=material_dico
)
ratio = N / N0
else:
ratio = 1
return ratio * n2_ref
def gas_n2(gas_name: str, pressure: float, temperature: float) -> float:
"""returns the nonlinear refractive index
@@ -421,7 +294,7 @@ def gas_n2(gas_name: str, pressure: float, temperature: float) -> float:
float
n2 in m2/W
"""
return non_linear_refractive_index(utils.load_material_dico(gas_name), pressure, temperature)
return Gas(gas_name).n2(temperature, pressure)
def gas_chi3(gas_name: str, wavelength: float, pressure: float, temperature: float) -> float:
@@ -441,11 +314,10 @@ def gas_chi3(gas_name: str, wavelength: float, pressure: float, temperature: flo
float
[description]
"""
mat_dico = utils.load_material_dico(gas_name)
chi = sellmeier_scalar(wavelength, mat_dico, pressure=pressure, temperature=temperature)
return n2_to_chi3(
non_linear_refractive_index(mat_dico, pressure, temperature), np.sqrt(chi + 1)
)
gas = Gas(gas_name)
n = gas.sellmeier.n(wavelength, temperature, pressure)
n2 = gas.n2(temperature, pressure)
return n2_to_chi3(n2, n)
def n2_to_chi3(n2: float, n0: float) -> float:

View File

@@ -1,12 +1,12 @@
from typing import Any, Callable, NamedTuple, TypeVar
from typing import Any, Callable, NamedTuple
import numpy as np
import scipy.special
from scipy.interpolate import interp1d
from numpy.core.numeric import zeros_like
from scipy.interpolate import interp1d
from ..math import cumulative_simpson, expm1_int
from .units import e, hbar, me
from scgenerator.math import cumulative_simpson, expm1_int
from scgenerator.physics.units import e, hbar, me
class PlasmaInfo(NamedTuple):

View File

@@ -15,18 +15,17 @@ from dataclasses import astuple, dataclass
from pathlib import Path
from typing import Literal, Tuple, TypeVar
import numba
import matplotlib.pyplot as plt
import numpy as np
from numpy import pi
from numpy.fft import fft, fftshift, ifft
from scipy.interpolate import UnivariateSpline, interp1d
from scipy.optimize import minimize_scalar
from scipy.optimize.optimize import OptimizeResult
from scipy.optimize._optimize import OptimizeResult
from ..defaults import default_plotting
from .. import math
from . import units
from scgenerator import math
from scgenerator.defaults import default_plotting
from scgenerator.physics import units
c = 299792458.0
hbar = 1.05457148e-34

View File

@@ -1,20 +1,20 @@
import multiprocessing
import multiprocessing.connection
import os
import warnings
from collections import defaultdict
from datetime import datetime
from logging import Logger
from pathlib import Path
from typing import Any, Generator, Iterator, Optional, Type, Union
import warnings
import numpy as np
from .. import solver, utils
from ..logger import get_logger
from ..operators import CurrentState
from ..parameter import FileConfiguration, Parameters
from ..pbar import PBars, ProgressBarActor, progress_worker
from scgenerator import solver, utils
from scgenerator.logger import get_logger
from scgenerator.operators import CurrentState
from scgenerator.parameter import FileConfiguration, Parameters
from scgenerator.pbar import PBars, ProgressBarActor, progress_worker
try:
import ray

View File

@@ -6,18 +6,18 @@ import matplotlib.gridspec as gs
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.axes import Axes
from matplotlib.figure import Figure
from matplotlib.colors import ListedColormap
from matplotlib.figure import Figure
from matplotlib.transforms import offset_copy
from scipy.interpolate import UnivariateSpline, interp1d
from scipy.interpolate import UnivariateSpline
from . import math
from .const import PARAM_SEPARATOR
from .defaults import default_plotting as defaults
from .math import abs2, linear_interp_2d, span
from .parameter import Parameters
from .physics import pulse, units
from .physics.units import PlotRange, sort_axis
from scgenerator import math
from scgenerator.const import PARAM_SEPARATOR
from scgenerator.defaults import default_plotting as defaults
from scgenerator.math import abs2, linear_interp_2d, span
from scgenerator.parameter import Parameters
from scgenerator.physics import pulse, units
from scgenerator.physics.units import PlotRange, sort_axis
RangeType = tuple[float, float, Union[str, Callable]]
NO_LIM = object()
@@ -563,7 +563,6 @@ def transform_mean_values(
np.ndarray, shape (m, n)
all the values
"""
AAA
if values.ndim != 2:
print(f"Shape was {values.shape}. Can only plot 2D arrays")
return
@@ -1133,7 +1132,5 @@ def annotate_fwhm(
else:
offset = -arrow_length_pts
x, y = (left, v_max / 2)
trans = offset_copy(
ax.transData, ax.get_figure(), offset, 0, "points"
)
trans = offset_copy(ax.transData, ax.get_figure(), offset, 0, "points")
ax.text(x, y, arrow_label, transform=trans, **text_kwargs)

View File

@@ -1,23 +1,22 @@
from __future__ import annotations
from collections import defaultdict
import logging
from abc import abstractmethod
from collections import defaultdict
from typing import Iterator, Type
import numba
import numpy as np
from .logger import get_logger
from .operators import (
from scgenerator.logger import get_logger
from scgenerator.operators import (
AbstractConservedQuantity,
CurrentState,
LinearOperator,
NonLinearOperator,
ValueTracker,
)
from .utils import get_arg_names
import warnings
from scgenerator.utils import get_arg_names
class IntegratorError(Exception):

View File

@@ -7,21 +7,21 @@ from typing import Callable, Iterator, Optional, Union
import matplotlib.pyplot as plt
import numpy as np
from . import math
from .const import PARAM_FN, SPEC1_FN, SPEC1_FN_N
from .logger import get_logger
from .parameter import Parameters
from .physics import pulse, units
from .physics.units import PlotRange
from .plotting import (
from scgenerator import math
from scgenerator.const import PARAM_FN, SPEC1_FN, SPEC1_FN_N
from scgenerator.legacy import translate_parameters
from scgenerator.logger import get_logger
from scgenerator.parameter import Parameters
from scgenerator.physics import pulse, units
from scgenerator.physics.units import PlotRange
from scgenerator.plotting import (
mean_values_plot,
propagation_plot,
single_position_plot,
transform_1D_values,
transform_2D_propagation,
)
from .utils import load_spectrum, simulations_list, load_toml
from .legacy import translate_parameters
from scgenerator.utils import load_spectrum, load_toml, simulations_list
class Spectrum(np.ndarray):

View File

@@ -1,6 +1,6 @@
from math import prod
import itertools
from collections.abc import MutableMapping, Sequence
from math import prod
from pathlib import Path
from typing import Any, Callable, Generator, Generic, Iterable, Iterator, Optional, TypeVar, Union
@@ -8,7 +8,7 @@ import numpy as np
from pydantic import validator
from pydantic.main import BaseModel
from .const import PARAM_SEPARATOR
from scgenerator.const import PARAM_SEPARATOR
T = TypeVar("T")

View File

@@ -6,7 +6,7 @@ import matplotlib.pyplot as plt
def main():
capillary_thickness = 1.4e-6
wl = np.linspace(200e-9, 2000e-9, 500)
n_gas_2 = sc.materials.n_gas_2(wl, "air", 3e5, 300, True)
n_gas_2 = sc.materials.n_gas_2(wl, "air", 3e5, 300)
resonances = []
for i in range(5):
t = sc.fiber.resonance_thickness(wl, i, n_gas_2, 40e-6)