예제 #1
0
 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])
예제 #2
0
    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
예제 #3
0
    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
예제 #4
0
 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
예제 #5
0
                                          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])
예제 #6
0
    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)
예제 #7
0
    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)