def __init__(self, name: str = default_name, length: float = 1.0, alpha: Optional[Union[List[float], Callable]] = None, alpha_order: int = 1, beta: Optional[Union[List[float], Callable]] = None, beta_order: int = 2, gamma: Optional[Union[float, Callable]] = None, sigma: float = cst.KERR_COEFF, eta: float = cst.XPM_COEFF, T_R: float = cst.RAMAN_COEFF, tau_1: float = cst.TAU_1, tau_2: float = cst.TAU_2, f_R: float = cst.F_R, core_radius: float = cst.CORE_RADIUS, NA: Union[float, Callable] = cst.NA, nl_approx: bool = True, ATT: bool = True, DISP: bool = True, SPM: bool = True, XPM: bool = False, FWM: bool = False, SS: bool = False, RS: bool = False, approx_type: int = cst.DEFAULT_APPROX_TYPE, method: str = "rk4ip", steps: int = 100, medium: str = cst.DEF_FIBER_MEDIUM, save: bool = False, save_all: bool = False) -> None: r""" Parameters ---------- name : The name of the component. length : The length of the fiber. :math:`[km]` 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}]` sigma : Positive term multiplying the XPM term of the NLSE eta : Positive term muiltiplying the XPM in other non linear terms of the NLSE T_R : The raman coefficient. :math:`[]` tau_1 : The inverse of vibrational frequency of the fiber core molecules. :math:`[ps]` tau_2 : The damping time of vibrations. :math:`[ps]` f_R : The fractional contribution of the delayed Raman response. :math:`[]` core_radius : The radius of the core. :math:`[\mu m]` NA : The numerical aperture. nl_approx : If True, the approximation of the NLSE is used. ATT : If True, trigger the attenuation. DISP : If True, trigger the dispersion. SPM : If True, trigger the self-phase modulation. XPM : If True, trigger the cross-phase modulation. FWM : If True, trigger the Four-Wave mixing. SS : bool If True, trigger the self-steepening. RS : If True, trigger the Raman scattering. approx_type : The type of the NLSE approximation. method : The solver method type steps : The number of steps for the solver medium : The main medium of the fiber. save : If True, the last wave to enter/exit a port will be saved. save_all : If True, save the wave at each spatial step in the component. """ # Parent constructor ------------------------------------------- ports_type = [cst.OPTI_ALL, cst.OPTI_ALL] super().__init__(name, default_name, ports_type, save) # Attr types check --------------------------------------------- util.check_attr_type(length, 'length', float) util.check_attr_type(alpha, 'alpha', None, Callable, float, List) util.check_attr_type(alpha_order, 'alpha_order', int) util.check_attr_type(beta, 'beta', None, Callable, float, list) util.check_attr_type(beta_order, 'beta_order', int) util.check_attr_type(gamma, 'gamma', None, float, Callable) util.check_attr_type(sigma, 'sigma', float) util.check_attr_type(eta, 'eta', float) util.check_attr_type(T_R, 'T_R', float) util.check_attr_type(tau_1, 'tau_1', float) util.check_attr_type(tau_2, 'tau_2', float) util.check_attr_type(f_R, 'f_R', float) util.check_attr_type(nl_approx, 'nl_approx', bool) util.check_attr_type(core_radius, 'core_radius', float) util.check_attr_type(NA, 'NA', float, Callable) util.check_attr_type(ATT, 'ATT', bool) util.check_attr_type(DISP, 'DISP', bool) util.check_attr_type(SPM, 'SPM', bool) util.check_attr_type(XPM, 'XPM', bool) util.check_attr_type(FWM, 'FWM', bool) util.check_attr_type(SS, 'SS', bool) util.check_attr_type(RS, 'RS', bool) util.check_attr_type(approx_type, 'approx_type', int) util.check_attr_type(method, 'method', str) util.check_attr_type(steps, 'steps', int) util.check_attr_type(medium, 'medium', str) # Attr --------------------------------------------------------- if (nl_approx): nlse = ANLSE(alpha, alpha_order, beta, beta_order, gamma, sigma, eta, T_R, core_radius, NA, ATT, DISP, SPM, XPM, FWM, SS, RS, approx_type, medium) else: if (SS): nlse = GNLSE(alpha, alpha_order, beta, beta_order, gamma, sigma, tau_1, tau_2, f_R, core_radius, NA, ATT, DISP, SPM, XPM, FWM, medium) else: nlse = NLSE(alpha, alpha_order, beta, beta_order, gamma, sigma, tau_1, tau_2, f_R, core_radius, NA, ATT, DISP, SPM, XPM, FWM, medium) # Special case for gnlse and rk4ip method if (SS and not nl_approx and (method == "rk4ip") and cst.RK4IP_GNLSE): method = "rk4ip_gnlse" step_method = "fixed" # to change later when implementing adaptative self._stepper = Stepper([nlse], [method], length, [steps], [step_method], save_all=save_all) # Policy ------------------------------------------------------- self.add_port_policy(([0], [1], True))
class FiberAmplifier(AbstractPassComp): r"""A non ideal Fiber Amplifier. Attributes ---------- name : str The name of the component. ports_type : list of int Type of each port of the component, give also the number of ports in the component. For types, see :mod:`optcom/utils/constant_values/port_types`. save : bool If True, the last wave to enter/exit a port will be saved. N_0 : numpy.ndarray of float The population in the ground state. N_1 : numpy.ndarray of float The population in the metastable state. power_signal_forward : numpy.ndarray of float Power of the foward propagating signal for each channel. power_signal_backward : numpy.ndarray of float Power of the backward propagating signal for each channel. power_ase_forward : numpy.ndarray of float Power of the foward propagating ase for each channel. power_ase_backward : numpy.ndarray of float Power of the backward propagating ase for each channel. power_pump_forward : numpy.ndarray of float Power of the foward propagating pump for each channel. power_pump_backward : numpy.ndarray of float Power of the backward propagating pump for each channel. Notes ----- Component diagram:: [0] _____________________ [1] / \ / \ [2] [3] [0] and [1] : signal and [2] and [3] : pump """ _nbr_instances: int = 0 _nbr_instances_with_default_name: int = 0 def __init__(self, name: str = default_name, length: float = 1.0, alpha: Optional[Union[List[float], Callable]] = None, alpha_order: int = 1, beta: Optional[Union[List[float], Callable]] = None, beta_order: int = 2, gamma: Optional[Union[float, Callable]] = None, gain_order: int = 1, sigma: float = cst.KERR_COEFF, eta: float = cst.XPM_COEFF, T_R: float = cst.RAMAN_COEFF, tau_1: float = cst.TAU_1, tau_2: float = cst.TAU_2, f_R: float = cst.F_R, nl_approx: bool = True, 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, nl_index: Optional[Union[float, Callable]] = None, ATT: bool = True, DISP: bool = True, SPM: bool = True, XPM: bool = False, FWM: bool = False, SS: bool = False, RS: bool = False, GS: bool = True, approx_type: int = cst.DEFAULT_APPROX_TYPE, medium: str = cst.DEF_FIBER_MEDIUM, dopant: str = cst.DEF_FIBER_DOPANT, method: str = "rk4ip", steps: int = 100, solver_order: str = 'following', error: float = 0.01, propagate_pump: bool = False, save: bool = False, save_all: bool = False, max_nbr_pass: Optional[List[int]] = None) -> None: r""" Parameters ---------- name : The name of the component. length : The length of the fiber. :math:`[km]` 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}]` gain_order : The order of the gain coefficients to take into account. (from the Rate Equations resolution) eta : Positive term muiltiplying the XPM in other non linear terms of the NLSE. T_R : The raman coefficient. :math:`[]` tau_1 : The inverse of vibrational frequency of the fiber core molecules. :math:`[ps]` tau_2 : The damping time of vibrations. :math:`[ps]` f_R : The fractional contribution of the delayed Raman response. :math:`[]` nl_approx : If True, the approximation of the NLSE is used. 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. nl_index : The non linear index. Used to calculate the non linear parameter. :math:`[m^2\cdot W^{-1}]` ATT : If True, trigger the attenuation. DISP : If True, trigger the dispersion. SPM : If True, trigger the self-phase modulation. XPM : If True, trigger the cross-phase modulation. FWM : If True, trigger the Four-Wave mixing. SS : If True, trigger the self-steepening. RS : If True, trigger the Raman scattering. GS : If True, trigger the gain saturation. approx_type : The type of the NLSE approximation. medium : The main medium of the fiber amplifier. dopant : The doped medium of the fiber amplifier. method : The solver method type steps : The number of steps for the solver solver_order: The order in which to solve RE and NLSE. Can be either "following" or "alternating". error : The error for convergence criterion of stepper resolution. propagate_pump : If True, the pump is propagated forward in the layout. save : If True, the last wave to enter/exit a port will be saved. save_all : If True, save the wave at each spatial step in the component. max_nbr_pass : No fields will be propagated if the number of fields which passed through a specific port exceed the specified maximum number of pass for this port. """ # Parent constructor ------------------------------------------- ports_type = [cst.OPTI_ALL, cst.OPTI_ALL, cst.OPTI_IN, cst.OPTI_IN] super().__init__(name, default_name, ports_type, save, wait=True, max_nbr_pass=max_nbr_pass) # Attr types check --------------------------------------------- util.check_attr_type(length, 'length', float) util.check_attr_type(alpha, 'alpha', None, Callable, float, List) util.check_attr_type(alpha_order, 'alpha_order', int) util.check_attr_type(beta, 'beta', None, Callable, float, list) util.check_attr_type(beta_order, 'beta_order', int) util.check_attr_type(gamma, 'gamma', None, float, Callable) util.check_attr_type(gain_order, 'gain_order', int) util.check_attr_type(sigma, 'sigma', float) util.check_attr_type(eta, 'eta', float) util.check_attr_type(T_R, 'T_R', float) util.check_attr_type(tau_1, 'tau_1', float) util.check_attr_type(tau_2, 'tau_2', float) util.check_attr_type(f_R, 'f_R', float) util.check_attr_type(nl_approx, 'nl_approx', bool) util.check_attr_type(sigma_a, 'sigma_a', None, float, list, Callable) util.check_attr_type(sigma_e, 'sigma_e', None, float, list, Callable) util.check_attr_type(n_core, 'n_core', None, float, list) util.check_attr_type(n_clad, 'n_clad', None, float, list) util.check_attr_type(NA, 'NA', None, float, list) util.check_attr_type(temperature, 'temperature', float) util.check_attr_type(tau_meta, 'tau_meta', float) util.check_attr_type(N_T, 'N_T', float) util.check_attr_type(core_radius, 'core_radius', float) util.check_attr_type(clad_radius, 'clad_radius', float) util.check_attr_type(area_doped, 'area_doped', None, float) util.check_attr_type(eta_s, 'eta_s', float) util.check_attr_type(eta_p, 'eta_p', float) util.check_attr_type(R_0, 'R_0', float) util.check_attr_type(R_L, 'R_L', float) util.check_attr_type(nl_index, 'nl_index', None, float, Callable) util.check_attr_type(ATT, 'ATT', bool) util.check_attr_type(DISP, 'DISP', bool) util.check_attr_type(SPM, 'SPM', bool) util.check_attr_type(XPM, 'XPM', bool) util.check_attr_type(FWM, 'FWM', bool) util.check_attr_type(SS, 'SS', bool) util.check_attr_type(RS, 'RS', bool) util.check_attr_type(GS, 'GS', bool) util.check_attr_type(approx_type, 'approx_type', int) util.check_attr_type(medium, 'medium', str) util.check_attr_type(dopant, 'dopant', str) util.check_attr_type(method, 'method', str) util.check_attr_type(steps, 'steps', int) util.check_attr_type(solver_order, 'solver_order', str) util.check_attr_type(error, 'error', float) util.check_attr_type(propagate_pump, 'propagate_pump', bool) # Attr --------------------------------------------------------- # Component equations ------------------------------------------ step_update: bool = False if (solver_order == 'following') else True re = RE2Fiber(sigma_a, sigma_e, n_core, n_clad, NA, temperature, tau_meta, N_T, core_radius, clad_radius, area_doped, eta_s, eta_p, R_0, R_L, medium, dopant, step_update) if (nl_approx): nlse = AmpANLSE(re, alpha, alpha_order, beta, beta_order, gamma, gain_order, sigma, eta, T_R, R_0, R_L, nl_index, ATT, DISP, SPM, XPM, FWM, SS, RS, approx_type, GS, medium, dopant) else: if (SS): nlse = AmpGNLSE(re, alpha, alpha_order, beta, beta_order, gamma, gain_order, sigma, tau_1, tau_2, f_R, R_0, R_L, nl_index, ATT, DISP, SPM, XPM, FWM, GS, medium, dopant) else: nlse = AmpNLSE(re, alpha, alpha_order, beta, beta_order, gamma, gain_order, sigma, tau_1, tau_2, f_R, R_0, R_L, nl_index, ATT, DISP, SPM, XPM, FWM, GS, medium, dopant) # Component stepper -------------------------------------------- # Special case for gnlse and rk4ip method if (SS and not nl_approx and (method == "rk4ip") and cst.RK4IP_GNLSE): method = "rk4ip_gnlse" step_method = "fixed" # for now, only works with "fixed" eqs = [re, nlse] stepper_method: List[str] if (solver_order == 'following'): stepper_method = ['shooting', 'forward'] else: stepper_method = ['shooting', 'shooting'] # if method is empty '', will directly call the equation object self._stepper = Stepper(eqs, ['', method], length, [steps], [step_method], solver_order, stepper_method, error=error, save_all=save_all) self.N_0: Array[float] self.N_1: Array[float] self.power_ase_forward: Array[float] self.power_ase_backward: Array[float] self.power_signal_forward: Array[float] self.power_signal_backward: Array[float] self.power_pump_forward: Array[float] self.power_pump_backward: Array[float] # Policy ------------------------------------------------------- if (propagate_pump): self.add_port_policy( ([0, 2], [1, 1], False), ([0, 3], [1, 1], False), ([1, 2], [0, 0], False), ([1, 3], [0, 1], False)) else: self.add_port_policy( ([0, 2], [1, -1], False), ([0, 3], [1, -1], False), ([1, 2], [0, -1], False), ([1, 3], [0, -1], False)) self.add_wait_policy([0, 2], [0, 3], [1, 2], [1, 3]) # ================================================================== def __call__(self, domain: Domain, ports: List[int], fields: List[Field]) -> Tuple[List[int], List[Field]]: output_ports: List[int] = [] output_fields: List[Field] = [] pump_ports: List[int] = [] pump_fields: List[Field] = [] # Sort fields -------------------------------------------------- i = 0 while (i < len(ports)): if (ports[i] == 2 or ports[i] == 3): # Port from pump pump_fields.append(fields.pop(i)) pump_ports.append(ports.pop(i)) i += 1 ports.extend(pump_ports) # Set shooting method ------------------------------------------ if (util.sum_elem_list(util.unique(ports)) == 3): self._stepper.start_shooting_backward() util.warning_terminal( "Counter propagating pulses in fiber " "amplifier not totally handled yet, might lead to unrealistic " "results.") else: self._stepper.start_shooting_forward() # Compute ------------------------------------------------------ output_fields = self._stepper(domain, fields, pump_fields) if (self._stepper.save_all): self.storages.append(self._stepper.storage) # Record RE parameters ----------------------------------------- re = self._stepper.equations[0] # If shooting method stops earlier than expected, those values # won't be accurate anymore. -> need a back up in RE2Fiber ? self.N_0 = re.N_0 self.N_1 = re.N_1 self.power_ase_forward = re.power_ase_forward self.power_ase_backward = re.power_ase_backward self.power_signal_forward = re.power_signal_forward self.power_signal_backward = re.power_signal_backward self.power_pump_forward = re.power_pump_forward self.power_pump_backward = re.power_pump_backward return self.output_ports(ports), output_fields
def __init__(self, name: str = default_name, length: float = 1.0, alpha: Optional[Union[List[float], Callable]] = None, alpha_order: int = 1, beta: Optional[Union[List[float], Callable]] = None, beta_order: int = 2, gamma: Optional[Union[float, Callable]] = None, gain_order: int = 1, sigma: float = cst.KERR_COEFF, eta: float = cst.XPM_COEFF, T_R: float = cst.RAMAN_COEFF, tau_1: float = cst.TAU_1, tau_2: float = cst.TAU_2, f_R: float = cst.F_R, nl_approx: bool = True, 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], nl_index: Optional[Union[float, Callable]] = None, ATT: bool = True, DISP: bool = True, SPM: bool = True, XPM: bool = False, FWM: bool = False, SS: bool = False, RS: bool = False, GS: bool = True, approx_type: int = cst.DEFAULT_APPROX_TYPE, medium: str = cst.DEF_FIBER_MEDIUM, dopant: str = cst.DEF_FIBER_DOPANT, method: str = "rk4ip", steps: int = 100, solver_order: str = 'following', error: float = 0.01, propagate_pump: bool = False, save: bool = False, save_all: bool = False) -> None: r""" Parameters ---------- name : The name of the component. length : The length of the fiber. :math:`[km]` 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}]` gain_order : The order of the gain coefficients to take into account. (from the Rate Equations resolution) eta : Positive term muiltiplying the XPM in other non linear terms of the NLSE. T_R : The raman coefficient. :math:`[]` tau_1 : The inverse of vibrational frequency of the fiber core molecules. :math:`[ps]` tau_2 : The damping time of vibrations. :math:`[ps]` f_R : The fractional contribution of the delayed Raman response. :math:`[]` nl_approx : If True, the approximation of the NLSE is used. 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]` nl_index : The non linear index. Used to calculate the non linear parameter. :math:`[m^2\cdot W^{-1}]` ATT : If True, trigger the attenuation. DISP : If True, trigger the dispersion. SPM : If True, trigger the self-phase modulation. XPM : If True, trigger the cross-phase modulation. FWM : If True, trigger the Four-Wave mixing. SS : If True, trigger the self-steepening. RS : If True, trigger the Raman scattering. GS : If True, trigger the gain saturation. approx_type : The type of the NLSE approximation. medium : The main medium of the fiber amplifier. dopant : The doped medium of the fiber amplifier. method : The solver method type steps : The number of steps for the solver solver_order: The order in which to solve RE and NLSE. Can be either "following" or "alternating". error : The error for convergence criterion of stepper resolution. propagate_pump : If True, the pump is propagated forward in the layout. save : If True, the last wave to enter/exit a port will be saved. save_all : If True, save the wave at each spatial step in the component. """ # Parent constructor ------------------------------------------- ports_type = [cst.OPTI_ALL, cst.OPTI_ALL, cst.OPTI_IN, cst.OPTI_IN] super().__init__(name, default_name, ports_type, save, wait=True) # Attr types check --------------------------------------------- util.check_attr_type(length, 'length', float) util.check_attr_type(alpha, 'alpha', None, Callable, float, List) util.check_attr_type(alpha_order, 'alpha_order', int) util.check_attr_type(beta, 'beta', None, Callable, float, list) util.check_attr_type(beta_order, 'beta_order', int) util.check_attr_type(gamma, 'gamma', None, float, Callable) util.check_attr_type(gain_order, 'gain_order', int) util.check_attr_type(sigma, 'sigma', float) util.check_attr_type(eta, 'eta', float) util.check_attr_type(T_R, 'T_R', float) util.check_attr_type(tau_1, 'tau_1', float) util.check_attr_type(tau_2, 'tau_2', float) util.check_attr_type(f_R, 'f_R', float) util.check_attr_type(nl_approx, 'nl_approx', bool) util.check_attr_type(sigma_a, 'sigma_a', None, float, list, Callable) util.check_attr_type(sigma_e, 'sigma_e', None, float, list, Callable) util.check_attr_type(n_core, 'n_core', None, float, list) util.check_attr_type(n_clad, 'n_clad', None, float, list) util.check_attr_type(NA, 'NA', None, float, list) util.check_attr_type(temperature, 'temperature', float) util.check_attr_type(tau_meta, 'tau_meta', float) util.check_attr_type(N_T, 'N_T', float) util.check_attr_type(core_radius, 'core_radius', float) util.check_attr_type(clad_radius, 'clad_radius', float) util.check_attr_type(area_doped, 'area_doped', None, float) util.check_attr_type(eta_s, 'eta_s', float) util.check_attr_type(eta_p, 'eta_p', float) util.check_attr_type(R_0, 'R_0', float) util.check_attr_type(R_L, 'R_L', float) util.check_attr_type(signal_width, 'signal_width', list) util.check_attr_type(nl_index, 'nl_index', None, float, Callable) util.check_attr_type(ATT, 'ATT', bool) util.check_attr_type(DISP, 'DISP', bool) util.check_attr_type(SPM, 'SPM', bool) util.check_attr_type(XPM, 'XPM', bool) util.check_attr_type(FWM, 'FWM', bool) util.check_attr_type(SS, 'SS', bool) util.check_attr_type(RS, 'RS', bool) util.check_attr_type(GS, 'GS', bool) util.check_attr_type(approx_type, 'approx_type', int) util.check_attr_type(medium, 'medium', str) util.check_attr_type(dopant, 'dopant', str) util.check_attr_type(method, 'method', str) util.check_attr_type(steps, 'steps', int) util.check_attr_type(solver_order, 'solver_order', str) util.check_attr_type(error, 'error', float) util.check_attr_type(propagate_pump, 'propagate_pump', bool) # Attr --------------------------------------------------------- # Component equations ------------------------------------------ step_update: bool = False if (solver_order == 'following') else True re = RE2Fiber(sigma_a, sigma_e, n_core, n_clad, NA, temperature, tau_meta, N_T, core_radius, clad_radius, area_doped, eta_s, eta_p, R_0, R_L, signal_width, medium, dopant, step_update) if (nl_approx): nlse = AmpANLSE(re, alpha, alpha_order, beta, beta_order, gamma, gain_order, sigma, eta, T_R, R_0, R_L, nl_index, ATT, DISP, SPM, XPM, FWM, SS, RS, approx_type, GS, medium, dopant) else: if (SS): nlse = AmpGNLSE(re, alpha, alpha_order, beta, beta_order, gamma, gain_order, sigma, tau_1, tau_2, f_R, R_0, R_L, nl_index, ATT, DISP, SPM, XPM, FWM, GS, medium, dopant) else: nlse = AmpNLSE(re, alpha, alpha_order, beta, beta_order, gamma, gain_order, sigma, tau_1, tau_2, f_R, R_0, R_L, nl_index, ATT, DISP, SPM, XPM, FWM, GS, medium, dopant) # Component stepper -------------------------------------------- # Special case for gnlse and rk4ip method if (SS and not nl_approx and (method == "rk4ip") and cst.RK4IP_GNLSE): method = "rk4ip_gnlse" step_method = "fixed" # for now, only works with "fixed" eqs = [re, nlse] stepper_method: List[str] if (solver_order == 'following'): stepper_method = ['shooting', 'forward'] else: stepper_method = ['shooting', 'shooting'] # if method is empty '', will directly call the equation object self._stepper = Stepper(eqs, ['', method], length, [steps], [step_method], solver_order, stepper_method, error=error, save_all=save_all) self.N_0: Array[float] self.N_1: Array[float] self.power_ase_forward: Array[float] self.power_ase_backward: Array[float] self.power_signal_forward: Array[float] self.power_signal_backward: Array[float] self.power_pump_forward: Array[float] self.power_pump_backward: Array[float] # Policy ------------------------------------------------------- if (propagate_pump): self.add_port_policy( ([0, 2], [1, 1], False), ([0, 3], [1, 1], False), ([1, 2], [0, 0], False), ([1, 3], [0, 1], False)) else: self.add_port_policy( ([0, 2], [1, -1], False), ([0, 3], [1, -1], False), ([1, 2], [0, -1], False), ([1, 3], [0, -1], False)) self.add_wait_policy([0, 2], [0, 3], [1, 2], [1, 3])
def __init__(self, name: str = default_name, length: float = 1.0, nbr_fibers: int = 2, alpha: OPTIONAL_LIST_CALL_FLOAT = None, alpha_order: int = 1, beta: OPTIONAL_LIST_CALL_FLOAT = None, beta_order: int = 2, gamma: Optional[Union[List[float], List[Callable]]] = None, kappa: Optional[List[List[List[float]]]] = None, sigma: List[float] = [cst.KERR_COEFF], sigma_cross: List[List[float]] = [[cst.KERR_COEFF_CROSS]], eta: float = cst.XPM_COEFF, T_R: float = cst.RAMAN_COEFF, tau_1: float = cst.TAU_1, tau_2: float = cst.TAU_2, f_R: float = cst.F_R, nl_approx: bool = True, NA: Union[List[float], List[Callable]] = [cst.NA], ATT: bool = True, DISP: bool = True, SPM: bool = True, XPM: bool = False, FWM: bool = False, SS: bool = False, RS: bool = False, ASYM: bool = True, COUP: bool = True, approx_type: int = cst.DEFAULT_APPROX_TYPE, medium: str = cst.DEF_FIBER_MEDIUM, c2c_spacing: List[List[float]] = [[cst.C2C_SPACING]], core_radius: List[float] = [cst.CORE_RADIUS], V: List[float] = [cst.V], n_0: List[float] = [cst.REF_INDEX], method: str = "rk4ip", steps: int = 100, save: bool = False, save_all: bool = False, wait: bool = False, max_nbr_pass: Optional[List[int]] = None) -> None: r""" Parameters ---------- name : The name of the component. length : The length of the coupler. :math:`[km]` nbr_fibers : The number of fibers in the coupler. 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}]` kappa : The coupling coefficients. :math:`[km^{-1}]` sigma : Positive term multiplying the XPM term of the NLSE. sigma_cross : Positive term multiplying the XPM term of the NLSE inbetween the fibers. eta : Positive term muiltiplying the XPM in other non linear terms of the NLSE. T_R : The raman coefficient. :math:`[]` tau_1 : The inverse of vibrational frequency of the fiber core molecules. :math:`[ps]` tau_2 : The damping time of vibrations. :math:`[ps]` f_R : The fractional contribution of the delayed Raman response. :math:`[]` NA : The numerical aperture. nl_approx : If True, the approximation of the NLSE is used. ATT : If True, trigger the attenuation. DISP : If True, trigger the dispersion. SPM : If True, trigger the self-phase modulation. XPM : If True, trigger the cross-phase modulation. FWM : If True, trigger the Four-Wave mixing. SS : If True, trigger the self-steepening. RS : If True, trigger the Raman scattering. ASYM : If True, trigger the asymmetry effects between cores. COUP : If True, trigger the coupling effects between cores. approx_type : The type of the NLSE approximation. medium : The main medium of the fiber. c2c_spacing : The center to center distance between two cores. :math:`[\mu m]` core_radius : The core radius. :math:`[\mu m]` V : The fiber parameter. n_0 : The refractive index outside of the waveguides. method : The solver method type steps : The number of steps for the solver save : If True, the last wave to enter/exit a port will be saved. save_all : If True, save the wave at each spatial step in the component. wait : If True, wait for another pulse in the anolog port [0 <-> 1, and 2 <-> 3] to launch the simulation. """ # Parent constructor ------------------------------------------- ports_type = [cst.OPTI_ALL for i in range(4)] super().__init__(name, default_name, ports_type, save, wait=wait, max_nbr_pass=max_nbr_pass) # Attr types check --------------------------------------------- util.check_attr_type(length, 'length', float) util.check_attr_type(nbr_fibers, 'nbr_fibers', int) util.check_attr_type(alpha, 'alpha', None, Callable, float, List) util.check_attr_type(alpha_order, 'alpha_order', int) util.check_attr_type(beta, 'beta', None, Callable, float, list) util.check_attr_type(beta_order, 'beta_order', int) util.check_attr_type(gamma, 'gamma', None, float, list, Callable) util.check_attr_type(kappa, 'kappa', None, float, list) util.check_attr_type(sigma, 'sigma', float, list) util.check_attr_type(sigma_cross, 'sigma_cross', float, list) util.check_attr_type(eta, 'eta', float) util.check_attr_type(T_R, 'T_R', float) util.check_attr_type(tau_1, 'tau_1', float) util.check_attr_type(tau_2, 'tau_2', float) util.check_attr_type(f_R, 'f_R', float) util.check_attr_type(nl_approx, 'nl_approx', bool) util.check_attr_type(NA, 'NA', float, list, Callable) util.check_attr_type(ATT, 'ATT', bool) util.check_attr_type(DISP, 'DISP', bool) util.check_attr_type(SPM, 'SPM', bool) util.check_attr_type(XPM, 'XPM', bool) util.check_attr_type(FWM, 'FWM', bool) util.check_attr_type(SS, 'SS', bool) util.check_attr_type(RS, 'RS', bool) util.check_attr_type(ASYM, 'ASYM', bool) util.check_attr_type(COUP, 'COUP', bool) util.check_attr_type(approx_type, 'approx_type', int) util.check_attr_type(medium, 'medium', str) util.check_attr_type(c2c_spacing, 'c2c_spacing', float, list) util.check_attr_type(core_radius, 'core_radius', float, list) util.check_attr_type(V, 'V', float, list) util.check_attr_type(n_0, 'n_0', float, list) util.check_attr_type(method, 'method', str) util.check_attr_type(steps, 'steps', int) # Attr --------------------------------------------------------- if (nl_approx): cnlse = CANLSE(nbr_fibers, alpha, alpha_order, beta, beta_order, gamma, kappa, sigma, sigma_cross, eta, T_R, NA, ATT, DISP, SPM, XPM, FWM, SS, RS, ASYM, COUP, approx_type, medium, c2c_spacing, core_radius, V, n_0) else: if (SS): cnlse = CGNLSE(nbr_fibers, alpha, alpha_order, beta, beta_order, gamma, kappa, sigma, sigma_cross, tau_1, tau_2, f_R, NA, ATT, DISP, SPM, XPM, FWM, ASYM, COUP, medium, c2c_spacing, core_radius, V, n_0) else: cnlse = CNLSE(nbr_fibers, alpha, alpha_order, beta, beta_order, gamma, kappa, sigma, sigma_cross, tau_1, tau_2, f_R, NA, ATT, DISP, SPM, XPM, FWM, ASYM, COUP, medium, c2c_spacing, core_radius, V, n_0) method_2 = 'euler' # only euler for now step_method = 'fixed' # only fixed for now self._stepper = Stepper([cnlse, cnlse], [method, method_2], length, [steps, steps], [step_method], "alternating", save_all=save_all) # Policy ------------------------------------------------------- self.add_port_policy(([0, 1], [2, 3], True)) self.add_wait_policy([0, 1], [2, 3])