def update(self, waves: Array[cst.NPFT], h: float, z: float) -> None: # Update the resonant and total index change ------------------- N_1 = self._N_1[self._step] # Signal ------------------------------------------------------- for i in range(len(self._center_omega_s)): n_0 = self._n_0_s[i] delta_n_s = self._res_index.n(self._omega_s[i], n_0, N_1) self._n_tot_s[i] = n_0 + delta_n_s NA = NumericalAperture.calc_NA(self._n_tot_s[i], self._n_clad_s[i]) self._A_eff_s[i] = self._eff_area_s(self._omega_s[i], NA) self._Gamma_s[i] = self._overlap_s(self._A_eff_s[i]) # Pump --------------------------------------------------------- for i in range(len(self._center_omega_p)): n_0 = self._n_0_p[i] delta_n_p = self._res_index.n(self._omega_p[i], n_0, N_1) self._n_tot_p[i] = n_0 + delta_n_p NA = NumericalAperture.calc_NA(self._n_tot_p[i], self._n_clad_p[i]) self._A_eff_p[i] = self._eff_area_s(self._omega_p[i], NA) self._Gamma_p[i] = self._overlap_p(self._A_eff_p[i])
def get_eff_area(self, omega, step): """Return the effective area. Assume that omega is part of current center omegas. Parameters ---------- omega : The angular frequency. :math:`[rad\cdot ps^{-1}]` step : The current step of the computation. Returns ------- : The effective area at the specified space step. :math:`[\mu m^2]` """ # Handle isinstance(omega, float) ------------------------------ revert = False if (isinstance(omega, float)): omega = np.array([omega]) revert = True # Getter ------------------------------------------------------- NA = NumericalAperture.calc_NA(self.get_n_core(omega, step), self.get_n_clad(omega, step)) res = np.zeros_like(omega) self._eff_area_s.NA = NA self._eff_area_p.NA = NA for i in range(len(omega)): if (util.is_float_in_list(omega[i], self._center_omega_s)): res[i] = self._eff_area_s(omega[i]) else: res[i] = self._eff_area_p(omega[i]) # Revert float type of omega ----------------------------------- if (revert): res = res[0] return res
def __init__(self, sigma_a: Optional[Union[List[float], Callable]] = None, sigma_e: Optional[Union[List[float], Callable]] = None, n_core: Optional[Union[float, List[float]]] = None, n_clad: Optional[Union[float, List[float]]] = None, NA: Optional[Union[float, List[float]]] = None, temperature: float = 293.15, tau_meta: float = cst.TAU_META, N_T: float = cst.N_T, core_radius: float = cst.CORE_RADIUS, clad_radius: float = cst.CLAD_RADIUS, area_doped: Optional[float] = None, eta_s: float = cst.ETA_SIGNAL, eta_p: float = cst.ETA_PUMP, R_0: float = cst.R_0, R_L: float = cst.R_L, signal_width: List[float] = [1.0], medium: str = cst.DEF_FIBER_MEDIUM, dopant: str = cst.DEF_FIBER_DOPANT, step_update: bool = False) -> None: r""" Parameters ---------- sigma_a : The absorption cross sections of the signal and the pump (1<=len(sigma_a)<=2). :math:`[nm^2]` If a callable is provided, varibale must be wavelength. :math:`[nm]` sigma_e : The emission cross sections of the signal and the pump (1<=len(sigma_a)<=2). :math:`[nm^2]` If a callable is provided, varibale must be wavelength. :math:`[nm]` n_core : The refractive index of the core. If the medium is not recognised by Optcom, at least two elements should be provided out of those three: n_core, n_clad, NA. n_clad : The refractive index of the cladding. If the medium is not recognised by Optcom, at least two elements should be provided out of those three: n_core, n_clad, NA. NA : The numerical aperture. If the medium is not recognised by Optcom, at least two elements should be provided out of those three: n_core, n_clad, NA. temperature : The temperature of the medium. :math:`[K]` tau_meta : The metastable level lifetime. :math:`[\mu s]` N_T : The total doping concentration. :math:`[nm^{-3}]` core_radius : The radius of the core. :math:`[\mu m]` clad_radius : The radius of the cladding. :math:`[\mu m]` area_doped : The doped area. :math:`[\mu m^2]` If None, will be approximated to the core area. eta_s : The background signal loss. :math:`[km^{-1}]` eta_p : The background pump loss. :math:`[km^{-1}]` R_0 : The reflectivity at the fiber start. R_L : The reflectivity at the fiber end. signal_width : The width of each channel of the signal. :math:`[ps]` medium : The main medium of the fiber amplifier. dopant : The doped medium of the fiber amplifier. step_update : If True, update the signal and pump power from the wave arrays at each space step. """ super().__init__(2) # 2 equations # Variable declaration ----------------------------------------- self._power_s_f: Array[float] = np.array([]) self._power_s_b: Array[float] = np.array([]) self._power_s_ref: Array[float] = np.array([]) self._power_p_f: Array[float] = np.array([]) self._power_p_b: Array[float] = np.array([]) self._power_p_ref: Array[float] = np.array([]) self._power_ase_f: Array[float] = np.array([]) self._power_ase_b: Array[float] = np.array([]) self._N_1: Array[float] = np.array([]) self._sigma_a_s: Array[float] = np.array([]) self._sigma_a_p: Array[float] = np.array([]) self._sigma_e_s: Array[float] = np.array([]) self._sigma_e_p: Array[float] = np.array([]) self._n_tot_s: Array[float] = np.array([]) self._n_tot_p: Array[float] = np.array([]) self._n_0_s: Array[float] = np.array([]) self._n_0_p: Array[float] = np.array([]) self._n_clad_s: Array[float] = np.array([]) self._n_clad_p: Array[float] = np.array([]) self._Gamma_s: Array[float] = np.array([]) self._Gamma_p: Array[float] = np.array([]) self._A_eff_s: Array[float] = np.array([]) self._A_eff_p: Array[float] = np.array([]) # Variable initialization -------------------------------------- self._coprop: bool = True self._step_update: bool = step_update self._signal_width = signal_width self._medium: str = medium self._dopant: str = dopant self._T: float = temperature self._N_T: float = N_T self._tau: float = tau_meta * 1e6 # us -> ps self._decay: float = 1 / self._tau if (area_doped is None): area_doped = (cst.PI * core_radius**2) # TO DO: make option cladding doped and thus A_d_p = A_cladding A_d_p = (cst.PI * core_radius**2) A_d_s = area_doped self._overlap_s = OverlapFactor(A_d_s) self._overlap_p = OverlapFactor(A_d_p) self._A_d_s = A_d_s * 1e6 # um^2 -> nm^2 # Doping region area, can be cladding or core self._A_d_p = area_doped * 1e6 # um^2 -> nm^2 self._core_radius = core_radius self._res_index: ResonantIndex = ResonantIndex(medium=self._dopant) # Set n_core and n_clad depending on NA (forget NA afterwards) # Assume that only core medium can be calculated with Sellmeier # equations. Could be changed later. Would be easier to have # also cladding medium set by Sellmeier but cladding medium # not always available. -> To Discuss self._calc_n_core: Optional[Sellmeier] = None self._calc_n_clad: Optional[Callable] = None if (NA is None and n_clad is None): util.warning_terminal("Must specify at least NA or n_clad, " "n_clad will be set to 0.") self._n_clad_s_value = 0.0 self._n_clad_p_value = 0.0 if (n_clad is not None): # default is NA is None n_clad_temp = util.make_list(n_clad, 2) self._n_clad_s_value = n_clad_temp[0] self._n_clad_p_value = n_clad_temp[1] if (n_core is None): if (NA is not None and n_clad is not None): n_clad_temp = util.make_list(n_clad, 2) self._n_0_s_value =\ NumericalAperture.calc_n_core(NA, n_clad_temp[0]) self._n_0_p_value =\ NumericalAperture.calc_n_core(NA, n_clad_temp[1]) else: self._calc_n_core = Sellmeier(medium=self._medium) if (NA is not None and n_clad is None): self._calc_n_clad = NumericalAperture.calc_n_clad NA_temp = util.make_list(NA, 2) self._NA_value_s = NA_temp[0] self._NA_value_p = NA_temp[1] else: n_core_: List[float] = util.make_list(n_core, 2) self._n_0_s_value = n_core_[0] self._n_0_p_value = n_core_[1] if (NA is not None and n_clad is None): self._n_clad_s_value =\ NumericalAperture.calc_n_clad(NA, n_core_[0]) self._n_clad_p_value =\ NumericalAperture.calc_n_clad(NA, n_core_[1]) self._eff_area_s = EffectiveArea(core_radius) self._eff_area_p = EffectiveArea(core_radius) self._eta_s = eta_s * 1e-12 # km^{-1} -> nm^{-1} self._eta_p = eta_p * 1e-12 # km^{-1} -> nm^{-1} self._factor_s = 1 / (cst.HBAR * self._A_d_s) self._factor_p = 1 / (cst.HBAR * self._A_d_p) self._absorp: Optional[Absorption] = None if (sigma_a is None): self._absorp = Absorption(dopant=dopant) else: if (callable(sigma_a)): self._absorp = Absorption(predict=sigma_a) else: sigma_a_: List[float] = util.make_list(sigma_a, 2) self._sigma_a_s_value = sigma_a_[0] self._sigma_a_p_value = sigma_a_[1] self._sigma_e_mccumber = False self._stimu: Optional[StimulatedEmission] = None if (sigma_e is None): self._sigma_e_mccumber = True else: if (callable(sigma_e)): self._stimu = StimulatedEmission(predict=sigma_e) else: sigma_e_: List[float] = util.make_list(sigma_e, 2) self._sigma_e_s_value = sigma_e_[0] self._sigma_e_p_value = sigma_e_[1] self._R_0 = R_0 self._R_L = R_L
def open(self, domain: Domain, *fields: List[Field]) -> None: super().open(domain, *fields) # Initialize angular frequency --------------------------------- self._samples = len(self._omega) self._omega_s = self._in_eq_waves(self._omega_all, 0) self._omega_p = self._in_eq_waves(self._omega_all, 1) # Iniate array for center omegas data -------------------------- self._center_omega_s = self._in_eq_waves(self._center_omega, 0) self._center_omega_p = self._in_eq_waves(self._center_omega, 1) # Signal channel width ---------------------------------------- signal_width = np.array( util.make_list(self._signal_width, len(self._center_omega_s))) self._width_omega_s = (1.0 / signal_width) * 2.0 * cst.PI # Initiate the variables array - power and pop. density -------- self._shape_step_s = (len(self._center_omega_s), self._samples) self._power_s_f = np.zeros((1, ) + self._shape_step_s) self._power_s_b = np.zeros((1, ) + self._shape_step_s) self._power_s_ref = np.zeros(self._shape_step_s) self._power_ase_f = np.zeros((1, ) + self._shape_step_s) self._power_ase_b = np.zeros((1, ) + self._shape_step_s) self._shape_step_p = (len(self._center_omega_p), self._samples) self._power_p_f = np.zeros((1, ) + self._shape_step_p) self._power_p_b = np.zeros((1, ) + self._shape_step_p) self._power_p_ref = np.zeros(self._shape_step_p) self._N_1 = np.zeros(1) # Initiate refractive index ------------------------------------ if (self._calc_n_core): self._n_0_s = self._calc_n_core.n(self._omega_s) self._n_0_p = self._calc_n_core.n(self._omega_p) else: self._n_0_s = np.ones(self._shape_step_s) * self._n_0_s_value self._n_0_p = np.ones(self._shape_step_p) * self._n_0_p_value if (self._calc_n_clad): NA_s = np.ones(self._shape_step_s) * self._NA_value_s NA_p = np.ones(self._shape_step_p) * self._NA_value_p self._n_clad_s = self._calc_n_clad(NA_s, self._n_0_s) self._n_clad_p = self._calc_n_clad(NA_p, self._n_0_p) else: self._n_clad_s = np.ones(self._shape_step_s) * self._n_clad_s_value self._n_clad_p = np.ones(self._shape_step_p) * self._n_clad_p_value self._n_tot_s = np.zeros(self._shape_step_s) self._n_tot_p = np.zeros(self._shape_step_p) # Initiate cross sections for each frequency ------------------- self._A_eff_s = np.zeros(self._shape_step_s) self._Gamma_s = np.zeros(self._shape_step_s) for i in range(len(self._center_omega_s)): NA = NumericalAperture.calc_NA(self._n_0_s[i], self._n_clad_s[i]) self._A_eff_s[i] = self._eff_area_s(self._omega_s[i], NA) self._Gamma_s[i] = self._overlap_s(self._A_eff_s[i]) self._A_eff_p = np.zeros(self._shape_step_p) self._Gamma_p = np.zeros(self._shape_step_p) for i in range(len(self._center_omega_p)): NA = NumericalAperture.calc_NA(self._n_0_p[i], self._n_clad_p[i]) self._A_eff_p[i] = self._eff_area_s(self._omega_p[i], NA) self._Gamma_p[i] = self._overlap_p(self._A_eff_p[i]) # Initiate cross sections for each frequency ------------------- if (self._absorp is not None): self._sigma_a_s = np.zeros(self._shape_step_s) self._sigma_a_p = np.zeros(self._shape_step_p) for i in range(len(self._center_omega_s)): self._sigma_a_s[i] =\ self._absorp.get_cross_section(self._omega_s[i]) for i in range(len(self._center_omega_p)): self._sigma_a_p[i] =\ self._absorp.get_cross_section(self._omega_p[i]) else: self._sigma_a_s = np.ones( self._shape_step_s) * self._sigma_a_s_value self._sigma_a_p = np.ones( self._shape_step_p) * self._sigma_a_p_value if (self._stimu is not None): self._sigma_e_s = np.zeros(self._shape_step_s) self._sigma_e_p = np.zeros(self._shape_step_p) for i in range(len(self._center_omega_s)): self._sigma_e_s[i] =\ self._stimu.get_cross_section(self._omega_s[i]) for i in range(len(self._center_omega_p)): self._sigma_e_p[i] =\ self._stimu.get_cross_section(self._omega_p[i]) else: if (self._sigma_e_mccumber): self._sigma_e_s = np.zeros(self._shape_step_s) self._sigma_e_p = np.zeros(self._shape_step_p) # must initiate here else: self._sigma_e_s = (np.ones(self._shape_step_s) * self._sigma_e_s_value) self._sigma_e_p = (np.ones(self._shape_step_p) * self._sigma_e_p_value) # Initiate counter --------------------------------------------- self._iter = -1 # -1 bcs increment in the first init. cond. self._call_counter = 0 self._step = 0 self._forward = True
n_core=n_core, n_clad=n_clad)) effective_area = EffectiveArea(core_radius=core_radius, NA=NA) print(effective_area(omega)) print( EffectiveArea.calc_effective_area(omega, core_radius=core_radius, NA=NA)) # With numpy ndarray lambdas = np.linspace(900, 1550, 100) omegas = Domain.lambda_to_omega(lambdas) n_core = np.linspace(1.42, 1.43, 100) n_clad = np.linspace(1.415, 1.425, 100) NA = NumericalAperture.calc_NA(n_core, n_clad) effective_area = EffectiveArea(core_radius=core_radius, NA=NA) res = effective_area(omegas) x_labels = ['Lambda'] y_labels = ['Effective Area'] plot_titles = ["Effective Area as a function of the wavelength"] plot.plot(lambdas, res, x_labels=x_labels, y_labels=y_labels, plot_titles=plot_titles, opacity=0.0, y_ranges=[2.5 * 1e-20, 3.5 * 1e-20])
def __init__(self, N_T: float, doped_area: Optional[float], n_core: FLOAT_COEFF_TYPE_OPTIONAL, n_clad: FLOAT_COEFF_TYPE_OPTIONAL, NA: FLOAT_COEFF_TYPE_OPTIONAL, v_nbr: FLOAT_COEFF_TYPE_OPTIONAL, eff_area: FLOAT_COEFF_TYPE_OPTIONAL, overlap: FLOAT_COEFF_TYPE_OPTIONAL, sigma_a: FLOAT_COEFF_TYPE_OPTIONAL, sigma_e: FLOAT_COEFF_TYPE_OPTIONAL, core_radius: float, clad_radius: float, medium_core: str, medium_clad: str, dopant: str, temperature: float, RESO_INDEX: bool, CORE_PUMPED: bool, CLAD_PUMPED: bool, NOISE: bool, STEP_UPDATE: bool) -> None: r""" Parameters ---------- N_T : The total doping concentration. :math:`[nm^{-3}]` doped_area : The doped area. :math:`[\mu m^2]` If None, will be set to the core area. n_core : The refractive index of the core. If a callable is provided, variable must be angular frequency. :math:`[ps^{-1}]` (1<=len(n_core)<=2 for signal and pump) n_clad : The refractive index of the cladding. If a callable is provided, variable must be angular frequency. :math:`[ps^{-1}]` (1<=len(n_clad)<=2 for signal and pump) NA : The numerical aperture. :math:`[]` If a callable is provided, variable must be angular frequency. :math:`[ps^{-1}]` (1<=len(NA)<=2 for signal and pump) v_nbr : The V number. :math:`[]` If a callable is provided, variable must be angular frequency. :math:`[ps^{-1}]` (1<=len(v_nbr)<=2 for signal and pump) eff_area : The effective area. :math:`[\u m^2]` If a callable is provided, variable must be angular frequency. :math:`[ps^{-1}]` (1<=len(eff_area)<=2 for signal and pump) overlap : The overlap factors of the signal and the pump. (1<=len(overlap)<=2). [signal, pump] If a callable is provided, the variable must be angular frequency. :math:`[ps^{-1}]` sigma_a : The absorption cross sections of the signal and the pump (1<=len(sigma_a)<=2). :math:`[nm^2]` [signal, pump] If a callable is provided, the variable must be angular frequency. :math:`[ps^{-1}]` sigma_e : The emission cross sections of the signal and the pump (1<=len(sigma_e)<=2). :math:`[nm^2]` [signal, pump] If a callable is provided, the variable must be angular frequency. :math:`[ps^{-1}]` core_radius : The radius of the core. :math:`[\mu m]` clad_radius : The radius of the cladding. :math:`[\mu m]` medium_core : The medium of the core. medium_clad : The medium of the cladding. dopant : The doping medium of the active fiber. temperature : The temperature of the fiber. :math:`[K]` RESO_INDEX : If True, trigger the resonant refractive index which will be added to the core refractive index. To see the effect of the resonant index, the flag STEP_UPDATE must be set to True in order to update the dispersion coefficient at each space step depending on the resonant index at each space step. CORE_PUMPED : If True, there is dopant in the core. CLAD_PUMPED : If True, there is dopant in the cladding. NOISE : If True, trigger the noise calculation. STEP_UPDATE : If True, update fiber parameters at each spatial sub-step. """ nbr_eqs = 4 super().__init__(nbr_eqs=nbr_eqs, prop_dir=[True, False, True, False], SHARE_WAVES=True, NOISE=NOISE, STEP_UPDATE=True, INTRA_COMP_DELAY=False, INTRA_PORT_DELAY=False, INTER_PORT_DELAY=False) n_core = util.make_list(n_core, 2) n_clad = util.make_list(n_clad, 2) NA = util.make_list(NA, 2) v_nbr = util.make_list(v_nbr, 2) eff_area = util.make_list(eff_area, 2) overlap = util.make_list(overlap, 2) sigma_a = util.make_list(sigma_a, 2) sigma_e = util.make_list(sigma_e, 2) # Alias -------------------------------------------------------- CLE = CallableLittExpr CC = CallableContainer # Doping concentration ----------------------------------------- self._N_T = N_T # Media -------------------------------------------------------- self._medium_core: str = medium_core self._medium_clad: str = medium_clad # Refractive indices and numerical aperture -------------------- self._n_core: List[Union[float, Callable]] = [] self._n_clad: List[Union[float, Callable]] = [] self._NA: List[Union[float, Callable]] = [] self._n_reso: List[ResonantIndex] = [] fct_calc_n_core = NumericalAperture.calc_n_core fct_calc_n_clad = NumericalAperture.calc_n_core n_core_pur_: Union[CallableLittExpr, CallableContainer, Sellmeier] n_core_: Union[CallableLittExpr, CallableContainer, Sellmeier] n_clad_: Union[CallableLittExpr, CallableContainer, NumericalAperture, Sellmeier] NA_: Callable n_reso_: ResonantIndex for i in range(2): crt_n_core = n_core[i] crt_n_clad = n_clad[i] crt_NA = NA[i] if (crt_n_core is not None): n_core_pur_ = CLE([np.ones_like, crt_n_core], ['*']) if (RESO_INDEX): n_reso_ = ResonantIndex(dopant, n_core_pur_, 0.0) n_core_ = CLE([n_core_pur_, n_reso_], ['+']) else: n_core_ = n_core_pur_ if (crt_n_clad is not None and crt_NA is not None): n_clad_ = CLE([np.ones_like, crt_n_clad], ['*']) NA_ = CLE([np.ones_like, crt_NA], ['*']) elif (crt_n_clad is not None): n_clad_ = CLE([np.ones_like, crt_n_clad], ['*']) NA_ = NumericalAperture(n_core_, n_clad_) elif (crt_NA is not None): NA_ = CLE([np.ones_like, crt_NA], ['*']) n_clad_ = CC(fct_calc_n_clad, [NA_, n_core_]) else: # n_clad and NA are None n_clad_ = Sellmeier(self._medium_clad, cst.FIBER_CLAD_DOPANT, cst.CLAD_DOPANT_CONCENT) NA_ = NumericalAperture(n_core_, n_clad_) else: if (crt_n_clad is not None and crt_NA is not None): n_clad_ = CLE([np.ones_like, crt_n_clad], ['*']) NA_ = CLE([np.ones_like, crt_NA], ['*']) n_core_pur_ = CC(fct_calc_n_core, [NA_, n_clad_]) if (RESO_INDEX): n_reso_ = ResonantIndex(dopant, n_core_pur_, 0.0) n_core_ = CLE([n_core_pur_, n_reso_], ['+']) else: n_core_ = n_core_pur_ else: n_core_pur_ = Sellmeier(self._medium_core, cst.FIBER_CORE_DOPANT, cst.CORE_DOPANT_CONCENT) if (RESO_INDEX): n_reso_ = ResonantIndex(dopant, n_core_pur_, 0.0) n_core_ = CLE([n_core_pur_, n_reso_], ['+']) else: n_core_ = n_core_pur_ if (crt_n_clad is not None): n_clad_ = CLE([np.ones_like, crt_n_clad], ['*']) NA_ = NumericalAperture(n_core_, n_clad_) elif (crt_NA is not None): NA_ = CLE([np.ones_like, crt_NA], ['*']) n_clad_ = CC(fct_calc_n_clad, [NA_, n_core_]) else: # all None n_clad_ = Sellmeier(self._medium_clad, cst.FIBER_CLAD_DOPANT, cst.CLAD_DOPANT_CONCENT) NA_ = NumericalAperture(n_core_, n_clad_) self._n_core.append(n_core_) self._n_clad.append(n_clad_) if (RESO_INDEX): self._n_reso.append(n_reso_) self._NA.append(NA_) # V number ----------------------------------------------------- self._v_nbr: List[Union[float, Callable]] = [] v_nbr_: Union[CallableLittExpr, VNumber] for i in range(2): crt_v_nbr = v_nbr[i] if (crt_v_nbr is None): v_nbr_ = VNumber(self._NA[i], core_radius) else: v_nbr_ = CLE([np.ones_like, crt_v_nbr], ['*']) self._v_nbr.append(v_nbr_) # Effective Area ----------------------------------------------- self._eff_area: List[Union[float, Callable]] = [] eff_area_: Union[CallableLittExpr, EffectiveArea] for i in range(2): crt_eff_area = eff_area[i] if (crt_eff_area is None): eff_area_ = EffectiveArea(self._v_nbr[i], core_radius) else: eff_area_ = CLE([np.ones_like, crt_eff_area], ['*']) self._eff_area.append(eff_area_) # Doped area --------------------------------------------------- core_area: float = cst.PI * (core_radius**2) clad_area: float = cst.PI * (clad_radius**2 - core_radius**2) self._doped_area: float if (doped_area is None): self._doped_area = core_area else: self._doped_area = doped_area # Overlap factor ----------------------------------------------- if (not CORE_PUMPED and not CLAD_PUMPED): warning_message: str = ( "CORE_PUMPED and CLAD_PUMPED are False, " "the fiber amplifier must be at least pumped in the " "core or in the cladding for lasing effect. CORE_PUMPED " "has been set to True.") warnings.warn(warning_message, PumpSchemeWarning) CORE_PUMPED = True self._overlap: List[Union[float, Callable]] = [] overlap_: Union[CallableLittExpr, OverlapFactor] clad_pump_overlap: Union[float, CallableLittExpr, OverlapFactor] core_pump_overlap: Union[float, CallableLittExpr, OverlapFactor] for i in range(2): crt_overlap = overlap[i] if (crt_overlap is None): if (not i): overlap_ = OverlapFactor(self._eff_area[i], self._doped_area) else: clad_pump_overlap = self._doped_area / clad_area core_pump_overlap = OverlapFactor(self._eff_area[i], self._doped_area) if (CORE_PUMPED and CLAD_PUMPED): overlap_ = CLE([core_pump_overlap, clad_pump_overlap], ['+']) elif (CLAD_PUMPED): overlap_ = CLE([np.ones_like, clad_pump_overlap], ['*']) else: # CORE_PUMPED (forced beforehand if wasn't) overlap_ = core_pump_overlap else: overlap_ = CLE([np.ones_like, crt_overlap], ['*']) self._overlap.append(overlap_) # Cross sections ----------------------------------------------- self._sigma_a: List[Union[float, Callable]] = [] self._sigma_e: List[Union[float, Callable]] = [] sigma_a_: Union[CallableLittExpr, AbsorptionSection] sigma_e_: Union[CallableLittExpr, EmissionSection] for i in range(2): crt_sigma_a = sigma_a[i] crt_sigma_e = sigma_e[i] if (crt_sigma_a is not None and crt_sigma_e is not None): sigma_a_ = CLE([np.ones_like, crt_sigma_a], ['*']) sigma_e_ = CLE([np.ones_like, crt_sigma_e], ['*']) elif (crt_sigma_a is not None): sigma_a_ = CLE([np.ones_like, crt_sigma_a], ['*']) sigma_e_ = EmissionSection(dopant, medium_core, temperature, sigma_a_) elif (crt_sigma_e is not None): sigma_e_ = CLE([np.ones_like, crt_sigma_e], ['*']) sigma_a_ = AbsorptionSection(dopant, medium_core, temperature, sigma_e_) else: # both None sigma_a_ = AbsorptionSection(dopant) sigma_e_ = EmissionSection(dopant, medium_core, temperature) self._sigma_a.append(sigma_a_) self._sigma_e.append(sigma_e_) # Population density ------------------------------------------- self._pop = np.zeros(0, dtype=np.float64)
def __init__(self, alpha: Optional[Union[List[float], Callable]], alpha_order: int, beta: Optional[Union[List[float], Callable]], beta_order: int, gamma: Optional[Union[float, Callable]], core_radius: float, clad_radius: float, n_core: Optional[Union[float, Callable]], n_clad: Optional[Union[float, Callable]], NA: Optional[Union[float, Callable]], v_nbr: Optional[Union[float, Callable]], eff_area: Optional[Union[float, Callable]], nl_index: Optional[Union[float, Callable]], medium_core: str, medium_clad: str, temperature: float, ATT: bool, DISP: bool, NOISE: bool, UNI_OMEGA: bool, STEP_UPDATE: bool, INTRA_COMP_DELAY: bool, INTRA_PORT_DELAY: bool, INTER_PORT_DELAY: bool) -> None: r""" Parameters ---------- alpha : The derivatives of the attenuation coefficients. :math:`[km^{-1}, ps\cdot km^{-1}, ps^2\cdot km^{-1}, ps^3\cdot km^{-1}, \ldots]` If a callable is provided, variable must be angular frequency. :math:`[ps^{-1}]` alpha_order : The order of alpha coefficients to take into account. (will be ignored if alpha values are provided - no file) beta : The derivatives of the propagation constant. :math:`[km^{-1}, ps\cdot km^{-1}, ps^2\cdot km^{-1}, ps^3\cdot km^{-1}, \ldots]` If a callable is provided, variable must be angular frequency. :math:`[ps^{-1}]` beta_order : The order of beta coefficients to take into account. (will be ignored if beta values are provided - no file) gamma : The non linear coefficient. :math:`[rad\cdot W^{-1}\cdot km^{-1}]` If a callable is provided, variable must be angular frequency. :math:`[ps^{-1}]` core_radius : The radius of the core. :math:`[\mu m]` clad_radius : The radius of the cladding. :math:`[\mu m]` n_core : The refractive index of the core. If a callable is provided, variable must be angular frequency. :math:`[ps^{-1}]` n_clad : The refractive index of the clading. If a callable is provided, variable must be angular frequency. :math:`[ps^{-1}]` NA : The numerical aperture. If a callable is provided, variable must be angular frequency. :math:`[ps^{-1}]` v_nbr : The V number. If a callable is provided, variable must be angular frequency. :math:`[ps^{-1}]` eff_area : The effective area. If a callable is provided, variable must be angular frequency. :math:`[ps^{-1}]` nl_index : The non-linear coefficient. If a callable is provided, variable must be angular frequency. :math:`[ps^{-1}]` medium_core : The medium of the fiber core. medium_clad : The medium of the fiber cladding. temperature : The temperature of the medium. :math:`[K]` ATT : If True, trigger the attenuation. DISP : If True, trigger the dispersion. NOISE : If True, trigger the noise calculation. UNI_OMEGA : If True, consider only the center omega for computation. Otherwise, considered omega discretization. STEP_UPDATE : If True, update component parameters at each spatial space step by calling the _update_variables method. INTRA_COMP_DELAY : If True, take into account the relative time difference, between all waves, that is acquired while propagating in the component. INTRA_PORT_DELAY : If True, take into account the initial relative time difference between channels of all fields but for each port. INTER_PORT_DELAY : If True, take into account the initial relative time difference between channels of all fields of all ports. """ super().__init__(nbr_eqs=1, SHARE_WAVES=False, prop_dir=[True], NOISE=NOISE, STEP_UPDATE=STEP_UPDATE, INTRA_COMP_DELAY=INTRA_COMP_DELAY, INTRA_PORT_DELAY=INTRA_PORT_DELAY, INTER_PORT_DELAY=INTER_PORT_DELAY) # media -------------------------------------------------------- self._medium_core: str = medium_core self._medium_clad: str = medium_clad # Refractive indices and numerical aperture -------------------- self._n_core: Union[float, Callable] self._n_clad: Union[float, Callable] self._NA: Union[float, Callable] fct_calc_n_core = NumericalAperture.calc_n_core fct_calc_n_clad = NumericalAperture.calc_n_core if (n_core is not None and n_clad is not None and NA is not None): self._n_core = n_core self._n_clad = n_clad self._NA = NA elif (n_core is not None and n_clad is not None): self._n_core = n_core self._n_clad = n_clad self._NA = NumericalAperture(self._n_core, self._n_clad) elif (n_core is not None and NA is not None): self._n_core = n_core self._NA = NA self._n_clad = CallableContainer(fct_calc_n_clad, [self._NA, self._n_core]) elif (n_clad is not None and NA is not None): self._n_clad = n_clad self._NA = NA self._n_core = CallableContainer(fct_calc_n_core, [self._NA, self._n_clad]) elif (n_core is not None): self._n_core = n_core self._n_clad = Sellmeier(medium_clad, cst.FIBER_CLAD_DOPANT, cst.CLAD_DOPANT_CONCENT) self._NA = NumericalAperture(self._n_core, self._n_clad) elif (n_clad is not None): self._n_clad = n_clad self._n_core = Sellmeier(medium_core, cst.FIBER_CORE_DOPANT, cst.CORE_DOPANT_CONCENT) self._NA = NumericalAperture(self._n_core, self._n_clad) elif (NA is not None): self._NA = NA self._n_core = Sellmeier(medium_core, cst.FIBER_CORE_DOPANT, cst.CORE_DOPANT_CONCENT) self._n_clad = CallableContainer(fct_calc_n_clad, [self._NA, self._n_core]) else: # all None self._n_core = Sellmeier(medium_core, cst.FIBER_CORE_DOPANT, cst.CORE_DOPANT_CONCENT) self._n_clad = Sellmeier(medium_clad, cst.FIBER_CLAD_DOPANT, cst.CLAD_DOPANT_CONCENT) self._NA = NumericalAperture(self._n_core, self._n_clad) # V number ----------------------------------------------------- self._v_nbr: Union[float, Callable] if (v_nbr is not None): self._v_nbr = v_nbr else: self._v_nbr = VNumber(self._NA, core_radius) # Effective Area ----------------------------------------------- self._eff_area: Union[float, Callable] if (eff_area is not None): self._eff_area = eff_area else: self._eff_area = EffectiveArea(self._v_nbr, core_radius) # Non-linear index --------------------------------------------- self._nl_index: Union[float, Callable] if (nl_index is not None): self._nl_index = nl_index else: self._nl_index = NLIndex(medium_core) # Non-linear coefficient --------------------------------------- self._predict_gamma: Optional[Callable] = None self._gamma: np.ndarray if (gamma is not None): if (callable(gamma)): self._predict_gamma = gamma else: self._gamma = np.asarray(util.make_list(gamma)) else: self._predict_gamma = NLCoefficient(self._nl_index, self._eff_area) # Effects ------------------------------------------------------ self._att: Optional[AbstractEffectTaylor] = None self._disp: Optional[AbstractEffectTaylor] = None if (ATT): if (alpha is not None): self._att = Attenuation(alpha, alpha_order, UNI_OMEGA=UNI_OMEGA) self._add_lin_effect(self._att, 0, 0) self._add_delay_effect(self._att) else: util.warning_terminal("Currently no method to calculate " "attenuation as a function of the medium. Must provide " "attenuation coefficient alpha, otherwise attenuation " "effect will be ignored.") # Even if DISP==False, need _beta in CNLSE self._beta: Union[List[float], Callable] if (beta is None): self._beta = ChromaticDisp(self._n_core) else: self._beta = beta if (DISP): self._disp = Dispersion(self._beta, beta_order, start_taylor=2, UNI_OMEGA=UNI_OMEGA) self._add_lin_effect(self._disp, 0, 0) self._add_delay_effect(self._disp)