Beispiel #1
0
 def set(self, waves: Array[cst.NPFT], h: float, z: float) -> None:
     self._step = int(round(z / h))
     self._call_counter += 1
     # Set parameters -----------------------------------------------
     if (self._sigma_e_mccumber):
         omega = FFT.ifftshift(
             self._omega)  # could also change in abstract equation
         for i in range(len(self._center_omega_s)):
             self._sigma_e_s[i] = McCumber.calc_cross_section_emission(
                 self._sigma_a_s[i], omega, 0.0, self.N_0[self._step - 1],
                 self.N_1[self._step - 1], self._T)
         for i in range(len(self._center_omega_p)):
             self._sigma_e_p[i] = McCumber.calc_cross_section_emission(
                 self._sigma_a_p[i], omega, 0.0, self.N_0[self._step - 1],
                 self.N_1[self._step - 1], self._T)
     # Add pump and signal power space step -------------------------
     if (not self._iter):  # first iteration
         to_add_s = np.zeros((1, ) + self._shape_step_s)
         to_add_p = np.zeros((1, ) + self._shape_step_p)
         self._power_s_f = np.vstack((self._power_s_f, to_add_s))
         self._power_s_b = np.vstack((to_add_s, self._power_s_b))
         self._power_p_f = np.vstack((self._power_p_f, to_add_p))
         self._power_p_b = np.vstack((to_add_p, self._power_p_b))
         self._power_ase_f = np.vstack((self._power_ase_f, to_add_s))
         self._power_ase_b = np.vstack((to_add_s, self._power_ase_b))
         if (self._coprop):  # First iteration forward
             self._N_1 = np.hstack((self._N_1, [0.0]))
         else:  # First iteration backward -> self._forward is False
             self._N_1 = np.hstack(([0.0], self._N_1))
             self._step = 0  # construct backward array in bottom-up
     # Set signal power ---------------------------------------------
     # Truth table:
     # if coprop :  iter |forward|   to do
     #              0    |   T   |   set pump
     #              1    |   F   |   set pump
     #              2    |   T   |   set pump & set signal
     # if counterprop:   iter|forward|   to do
     #                   0   |   T   |   set pump
     #                   1   |   F   |   set pump & set signal
     if (self._step_update):
         if (self._forward):
             if (self._signal_on):
                 self._power_s_f[self._step - 1] = self._get_power_s(waves)
             self._power_p_f[self._step - 1] = self._get_power_p(waves)
         else:
             if (self._signal_on):
                 self._power_s_b[self._step + 1] = self._get_power_s(waves)
             self._power_p_b[self._step + 1] = self._get_power_p(waves)
Beispiel #2
0
    def op_approx_cross(
            self,
            waves: Array[cst.NPFT],
            id: int,
            corr_wave: Optional[Array[cst.NPFT]] = None) -> Array[cst.NPFT]:
        """The approximation operator of the cross terms of the Raman
        effect."""
        res = np.zeros(waves[id].shape, dtype=cst.NPFT)
        if (self._approx_type == cst.approx_type_1
                or self._approx_type == cst.approx_type_2
                or self._approx_type == cst.approx_type_3):
            for i in range(len(waves)):
                if (i != id):
                    res += waves[i] * np.conj(waves[i])
            res = FFT.dt_to_fft(res, self._omega, 1)

        return -1j * self._T_R * self._eta * res
Beispiel #3
0
    def calc_raman_gain(omega_bw: float, h_R: Array[float],
                        center_omega: float, n_0: float, f_R: float,
                        n_2: float) -> Array[float]:
        r"""Calculate the Raman gain.

        Parameters
        ----------
        omega_bw :
            The angular frequency bandwidth. :math:`[ps^{-1}]`
        h_R :
            The raman response function. :math:`[ps^{-1}]`
        center_omega :
            The center angular frequency. :math:`[ps^{-1}]`
        n_0 :
            The refractive index.
        f_R :
            The fractional contribution of the delayed Raman response.
            :math:`[]`
        n_2 :
            The non-linear index. :math:`[m^2\cdot W^{-1}]`

        Returns
        -------
        :
            The Raman gain.

        Notes
        -----

        .. math::  g_R(\Delta \omega) = \frac{\omega_0}{c n_0} f_R
                   \chi^{(3)} \Im{\hat{h}_R(\Delta \omega)}

        where:

        .. math::  \chi^{(3)} = \frac{4\epsilon_0 c n^2}{3} n_2

        :math:`\chi^{(3)}` is in :math:`[m^2 \cdot V^{-2}]`.

        """

        n_2 *= 1e36  # m^2 W^{-1} = s^3 kg^-1 -> ps^3 kg^-1
        chi_3 = 4 * cst.EPS_0 * cst.LIGHT_SPEED * n_0**2 * n_2 / 3

        return (center_omega / cst.LIGHT_SPEED / n_0 * f_R * chi_3 *
                np.imag(FFT.fft(h_R)))
Beispiel #4
0
    def open(self, domain: Domain, *fields: List[Field]) -> None:
        """This function is called once before a Stepper began the
        computation. Pass the time, wavelength and center wavelength
        to all the effects in the equation.
        """

        self._init_eq_ids(list(fields))

        self._center_omega = np.array([])
        for field_list in fields:
            for field in field_list:
                self._center_omega = np.hstack(
                    (self._center_omega, field.center_omega))

        self._omega = FFT.fftshift(domain.omega)

        effects = ["lin", "non_lin", "all"]
        for effect in effects:
            effect_list = getattr(self, "_effects_{}".format(effect))
            for i in range(len(effect_list)):
                effect_list[i].omega = self._omega
                effect_list[i].time = domain.time
                effect_list[i].center_omega = self._center_omega
Beispiel #5
0
    def op_non_lin(self, waves: Array[cst.NPFT], id: int,
                   corr_wave: Optional[Array[cst.NPFT]] = None
                   ) -> Array[cst.NPFT]:
        r"""Represent the non linear effects of the approximated NLSE.

        Parameters
        ----------
        waves :
            The wave packet propagating in the fiber.
        id :
            The ID of the considered wave in the wave packet.
        corr_wave :
            Correction wave, use for consistency.

        Returns
        -------
        :
            The non linear term for the considered wave.

        Notes
        -----

        .. math:: \hat{N} = \mathcal{F}^{-1}\bigg\{i \gamma
                  \Big(1+\frac{\omega}{\omega_0}\Big)
                  \mathcal{F}\Big\{ (1-f_R) |A|^2
                  + f_R \mathcal{F}^{-1}\big\{\mathcal{F}\{h_R\}
                  \mathcal{F}\{|A|^2\}\big\}\Big\}\bigg\}

        """
        res = FFT.ifft(self.op_non_lin_rk4ip(waves, id) * waves[id])
        if (corr_wave is None):
            corr_wave = waves[id]
        res = np.zeros_like(res)
        res = np.divide(res, corr_wave, out=res, where=corr_wave!=0)

        return res
Beispiel #6
0
    def rk4ip_gnlse(f: AbstractFieldEquation, waves: np.ndarray, z: float,
                    h: float) -> np.ndarray:
        r"""Optimized Runge-Kutta interaction picture method.

        Parameters
        ----------
        f :
            The function to compute.
        waves :
            The value of the unknown (waves) at the considered
            space step.
        z :
            The current value of the space variable.
        h :
            The step size.

        Returns
        -------
        :
            The one step euler computation results.

        Notes
        -----

        Implementation:

        .. math::
              \begin{align}
                &A^L_j = \exp\Big(\frac{h}{2}\hat{\mathcal{D}}\Big)
                    \mathcal{F}\{A_j(z)\} &\forall j=1,\ldots,K\\
                &k_0 = h \exp\Big(\frac{h}{2}\hat{\mathcal{D}}\Big)
                    \hat{\mathcal{N}}_0\big(A_1(z), \ldots, A_j(z),
                    \ldots, A_K(z)\big)&\forall j=1,\ldots,K\\
                &k_1 = h \hat{\mathcal{N}}_0\Big(\mathcal{F}^{-1}
                    \Big\{A^L_{1} +\frac{k_{0,1}}{2},\ldots,
                    A^L_{j}+\frac{k_{0,j}}{2},\ldots, A^L_{K}
                    + \frac{k_{0,K}}{2}\Big\} \Big)
                    &\forall j=1,\ldots,K\\
                &k_2 = h \hat{\mathcal{N}}_0\Big(\mathcal{F}^{-1}
                    \Big\{A^L_{1} +\frac{k_{1,1}}{2},\ldots, A^L_{j}
                    +\frac{k_{1,j}}{2},\ldots, A^L_{K}
                    + \frac{k_{1,K}}{2}\Big\} \Big)
                    &\forall j=1,\ldots,K\\
                &k_3 = h \hat{\mathcal{N}}_0\Big(\mathcal{F}^{-1}
                    \Big\{\exp\Big(\frac{h}{2}\hat{\mathcal{D}}\Big)
                    (A^L_1 + k_{2, 1}) \Big\},\ldots, \nonumber \\
                & \qquad \qquad \quad \mathcal{F}^{-1}\Big\{\exp
                    \Big(\frac{h}{2}\hat{\mathcal{D}}\Big)(A^L_j
                    + k_{2,j}) \Big\}, \ldots,\nonumber\\
                & \qquad \qquad \quad \mathcal{F}^{-1}\Big\{\exp\Big(
                    \frac{h}{2}\hat{\mathcal{D}}\Big)(A^L_K + k_{2,K})
                    \Big\}\Big)&\forall j=1,\ldots,K\\
                &A(z+h) = \mathcal{F}^{-1}\Big\{\frac{k_{3,j}}{6}
                    +\exp\Big(\frac{h}{2}\hat{\mathcal{D}}\Big)
                    \big(A^L_{j}+\frac{k_{0,j}}{6}+\frac{k_{1,j}}{3}
                    +\frac{k_{2,j}}{3}\big)\Big\} &\forall j=1,\ldots,K
              \end{align}

        where :math:`K` is the number of channels.

        """
        if (isinstance(f, GNLSE) or isinstance(f, AmpGNLSE)):
            h_h = 0.5 * h
            exp_op_lin = np.zeros_like(waves)
            A_L = np.zeros_like(waves)
            k_0 = np.zeros_like(waves)
            k_1 = np.zeros_like(waves)
            k_2 = np.zeros_like(waves)
            k_3 = np.zeros_like(waves)
            for i in range(len(waves)):
                exp_op_lin[i] = f.exp_op_lin(waves, i, h_h)
            for i in range(len(waves)):
                A_L[i] = exp_op_lin[i] * FFT.fft(waves[i])
            for i in range(len(waves)):
                k_0[i] = h * exp_op_lin[i] * f.term_rk4ip_non_lin(waves, i, z)
            for i in range(len(waves)):
                waves[i] = FFT.ifft(A_L[i] + 0.5*k_0[i])
            for i in range(len(waves)):
                k_1[i] = h * f.term_rk4ip_non_lin(waves, i, z)
            for i in range(len(waves)):
                waves[i] = FFT.ifft(A_L[i] + 0.5*k_1[i])
            for i in range(len(waves)):
                k_2[i] = h * f.term_rk4ip_non_lin(waves, i, z)
            for i in range(len(waves)):
                waves[i] = FFT.ifft(exp_op_lin[i] * (A_L[i] + k_2[i]))
            for i in range(len(waves)):
                k_3[i] = h * f.term_rk4ip_non_lin(waves, i, z)
            for i in range(len(waves)):
                waves[i] = ((k_3[i]/6.0)
                            + (exp_op_lin[i] * (A_L[i] + k_0[i]/6.0
                                                + (k_1[i]+k_2[i])/3.0)))
                waves[i] = FFT.ifft(waves[i])
        else:

            raise RK4IPGNLSEError("Only the the gnlse can be computed with "
                "the rk4ip_gnlse method.")

        return waves