Exemplo n.º 1
0
    def __init__(self,
                 name: str = default_name,
                 channels: int = 1,
                 center_lambda: List[float] = [cst.DEF_LAMBDA],
                 peak_power: List[float] = [1e-3],
                 total_power: Optional[List[float]] = None,
                 offset_nu: List[float] = [0.0],
                 init_phi: List[float] = [0.0],
                 save: bool = False) -> None:
        r"""
        Parameters
        ----------
        name :
            The name of the component.
        channels :
            The number of channels in the field.
        center_lambda :
            The center wavelength of the channels. :math:`[nm]`
        peak_power :
            Peak power of the pulses. :math:`[W]`
        total_power :
            Total power of the pulses. :math:`[W]` (peak_power will be
            ignored if total_power provided)
        offset_nu :
            The offset frequency. :math:`[THz]`
        init_phi :
            The initial phase of the pulses.
        save :
            If True, the last wave to enter/exit a port will be saved.

        """
        # Parent constructor -------------------------------------------
        ports_type = [cst.OPTI_OUT]
        super().__init__(name, default_name, ports_type, save)
        # Attr types check ---------------------------------------------
        util.check_attr_type(channels, 'channels', int)
        util.check_attr_type(center_lambda, 'center_lambda', float, list)
        util.check_attr_type(peak_power, 'peak_power', float, list)
        util.check_attr_type(total_power, 'total_power', None, float, list)
        util.check_attr_type(offset_nu, 'offset_nu', float, list)
        util.check_attr_type(init_phi, 'init_phi', float, list)
        # Attr ---------------------------------------------------------
        self.channels: int = channels
        self.center_lambda: List[float] = util.make_list(
            center_lambda, channels)
        self.peak_power: List[float] = util.make_list(peak_power, channels)
        self.total_power: List[float] = []
        if (total_power is not None):
            self.total_power = util.make_list(total_power, channels)
        self.offset_nu: List[float] = util.make_list(offset_nu, channels)
        self.init_phi: List[float] = util.make_list(init_phi, channels)
Exemplo n.º 2
0
    def __init__(self, kappa: Optional[List[float]] = None,
                 V: float = cst.V, a: float = cst.CORE_RADIUS,
                 d: float = cst.C2C_SPACING,
                 lambda_0: float = cst.DEF_LAMBDA,
                 n_0: float = cst.REF_INDEX,
                 omega: Optional[Array[float]] = None) -> None:
        r"""
        Parameters
        ----------
        kappa :
            The coupling coefficients. :math:`[km^{-1}]`
        V :
            The fiber parameter.
        a :
            The core radius. :math:`[\mu m]`
        d :
            The center to center spacing between the two cores.
            :math:`[\mu m]`
        lambda_0 :
            The wavelength in the vacuum for the considered wave.
            :math:`[nm]`
        n_0 :
            The refractive index outside of the two fiber cores.
        omega :
            The angular frequency. :math:`[ps^{-1}]`

        """
        super().__init__(omega)
        self._kappa: List[float]
        if (kappa is None):
            self._kappa = [Coupling.calc_kappa(V, a, d, lambda_0, n_0)]
        else:
            self._kappa = util.make_list(kappa)
Exemplo n.º 3
0
    def __init__(self, kappa: Optional[List[float]] = None,
                 V: float = cst.V, a: float = cst.CORE_RADIUS,
                 d: float = cst.C2C_SPACING,
                 n_0: float = cst.REF_INDEX) -> None:
        r"""
        Parameters
        ----------
        kappa :
            The coupling coefficients. :math:`[km^{-1}]`
        V :
            The fiber parameter.
        a :
            The core radius. :math:`[\mu m]`
        d :
            The center to center spacing between the two cores.
            :math:`[\mu m]`
        n_0 :
            The refractive index outside of the two fiber cores.

        """
        super().__init__()
        self._kappa: List[float]
        self._predict: Optional[Callable] = None
        self._V: float = V
        self._a: float = a
        self._d: float = d
        self._n_0: float = n_0
        if (kappa is not None):
            kappa = util.make_list(kappa)   # make sure is list
            self._kappa = np.asarray(kappa).reshape((1,-1))
        else:
            self._predict = self.get_kappa
Exemplo n.º 4
0
 def phase_shift(self, phase_shift: Union[List[float],
                                          List[Callable]]) -> None:
     phase_shift_ = util.make_list(phase_shift, 2, 0.0)
     self._phasemod_1 = IdealPhaseMod(name='nocount',
                                      phase_shift=phase_shift_[0])
     self._phasemod_2 = IdealPhaseMod(name='nocount',
                                      phase_shift=phase_shift_[1])
Exemplo n.º 5
0
    def __init__(self, name: str = default_name,
                 fields: Union[Field, List[Field]] = [], save: bool = False,
                 pre_call_code: str = '', post_call_code: str = '') -> None:
        r"""
        Parameters
        ----------
        name :
            The name of the component.
        fields :
            A field or a list of Field to launch into the simulation.
        pre_call_code :
            A string containing code which will be executed prior to
            the call to the function :func:`__call__`. The two
            parameters `input_ports` and `input_fields` are available.
        post_call_code :
            A string containing code which will be executed posterior to
            the call to the function :func:`__call__`. The two
            parameters `output_ports` and `output_fields` are available.

        """
        # Parent constructor -------------------------------------------
        ports_type = [cst.ANY_OUT]
        super().__init__(name, default_name, ports_type, save,
                         pre_call_code=pre_call_code,
                         post_call_code=post_call_code)
        # Attr types check ---------------------------------------------
        util.check_attr_type(fields, 'fields', Field, list)
        # Attr ---------------------------------------------------------
        self.fields: List[Field] = util.make_list(fields)
Exemplo n.º 6
0
    def __init__(self, kappa: Union[List[float], Callable],
                 order_taylor: int = 1, start_taylor: int = 0,
                 skip_taylor: List[int] = []) -> None:
        r"""
        Parameters
        ----------
        kappa :
            The coupling coefficients. :math:`[km^{-1}]` If a callable
            is provided, variable must be angular frequency.
            :math:`[ps^{-1}]`
        order_taylor :
            The order of kappa coefficients Taylor series expansion to
            take into account. (will be set to the length of the kappa
            array if one is provided)
        start_taylor :
            The order of the derivative from which to start the Taylor
            series expansion.
        skip_taylor :
            The order_taylors of the derivative to not consider.

        """
        super().__init__()
        self._order_taylor: int = order_taylor
        self._start_taylor: int = start_taylor
        self._skip_taylor: List[int] = skip_taylor
        # The coupling coefficient -------------------------------------
        self._op: np.ndarray = np.array([])
        self._kappa_op: np.ndarray = np.array([])
        self._kappa: Callable
        if (callable(kappa)):
            self._kappa = kappa
        else:
            kappa_ = np.asarray(util.make_list(kappa))
            self._kappa = lambda omega: util.hstack_like(kappa_, omega)
            self._order_taylor = len(kappa_) - 1
Exemplo n.º 7
0
    def transfer_function(time: np.ndarray, v_pi: List[float],
                          v_bias: List[float],
                          v_mod: List[Union[float, Callable]]) -> np.ndarray:

        v_pi = util.make_list(v_pi, 2)
        v_bias = util.make_list(v_bias, 2)
        v_mod = util.make_list(v_mod, 2)
        v_mod_: List[Callable] = []
        for v in v_mod:
            if (callable(v)):
                v_mod_.append(v)
            else:
                v_mod_.append(lambda t: v)
        print(v_pi, v_bias, v_mod_)
        phase_shift = [
            lambda t: cst.PI * (v_bias[0] + v_mod_[0](t)) / v_pi[0],
            lambda t: cst.PI * (v_bias[1] + v_mod_[1](t)) / v_pi[1]
        ]
        tf = np.cos((phase_shift[0](time) - phase_shift[1](time)) / 2.)

        return Field.temporal_power(tf)
Exemplo n.º 8
0
def add_single_plot(plt_to_add, x_data, y_data, x_label, y_label, x_range,
                    y_range, plot_title, plot_label, plot_linestyle,
                    plot_color, opacity):
    if (y_data.ndim == 1):  # not multidimentsional
        y_data = y_data.reshape((1, -1))
    if (cst.AUTO_PAD_PLOT):
        x_data = np.asarray(x_data)
        x_data, y_data = util.auto_pad(x_data, y_data)
    multi_channel = len(y_data) > 1
    labels_on_plot = plot_label is not None
    colors_on_plot = plot_color is not None
    if (multi_channel):
        plot_label = util.make_list(plot_label, len(y_data))
    for i in range(len(y_data)):
        if (multi_channel):
            if (labels_on_plot):
                plot_label_temp = plot_label[i] + " (ch.{})".format(i)
            else:
                plot_label_temp = "channel {}".format(i)
        else:
            plot_label_temp = plot_label
        if (not colors_on_plot):
            if (labels_on_plot or multi_channel):
                plt_to_add.plot(x_data,
                                y_data[i],
                                ls=plot_linestyle,
                                label=plot_label_temp)
            else:
                plt_to_add.plot(x_data, y_data[i], ls=plot_linestyle)
            plt_to_add.fill_between(x_data, y_data[i], alpha=opacity)
        else:
            if (labels_on_plot or multi_channel):
                plt_to_add.plot(x_data,
                                y_data[i],
                                ls=plot_linestyle,
                                c=plot_color,
                                label=plot_label_temp)
            else:
                plt_to_add.plot(x_data,
                                y_data[i],
                                ls=plot_linestyle,
                                c=plot_color)
            plt_to_add.fill_between(x_data,
                                    y_data[i],
                                    alpha=opacity,
                                    facecolor=plot_color)
        add_subplot_para(plt_to_add, x_label, y_label, x_range, y_range,
                         plot_title)
        if (labels_on_plot or multi_channel):
            plt_to_add.legend(loc="best")
Exemplo n.º 9
0
    def __init__(
        self,
        name: str = default_name,
        ratios_ports: List[List[float]] = [[0.5, 0.5]],
        max_nbr_pass: Optional[List[int]] = None,
        save: bool = False,
    ) -> None:
        """
        Parameters
        ----------
        name :
            The name of the component.
        ratios_ports :
            Each element of the list contain a list with the two
            dividing percentages for the two output ports.
        max_nbr_pass :
            The maximum number of times a field can enter at the
            corresponding index-number port.
        save :
            If True, the last wave to enter/exit a port will be saved.

        """
        # Parent constructor -------------------------------------------
        ports_type = [cst.ANY_ALL for i in range(4)]
        super().__init__(name,
                         default_name,
                         ports_type,
                         save,
                         max_nbr_pass=max_nbr_pass)
        # Attr types check ---------------------------------------------
        util.check_attr_type(ratios_ports, 'ratios_ports', list)
        # Attr ---------------------------------------------------------
        ratios_ports = util.make_list(ratios_ports, 4)
        # N.B. name='nocount' to avoid inc. default name counter
        self._divider_0 = IdealDivider(name='nocount',
                                       arms=2,
                                       divide=True,
                                       ratios=ratios_ports[0])
        self._divider_1 = IdealDivider(name='nocount',
                                       arms=2,
                                       divide=True,
                                       ratios=ratios_ports[1])
        self._divider_2 = IdealDivider(name='nocount',
                                       arms=2,
                                       divide=True,
                                       ratios=ratios_ports[2])
        self._divider_3 = IdealDivider(name='nocount',
                                       arms=2,
                                       divide=True,
                                       ratios=ratios_ports[3])
Exemplo n.º 10
0
    def __init__(self,
                 coeff: Union[List[float], Callable],
                 order_taylor: int = 1,
                 start_taylor: int = 0,
                 skip_taylor: List[int] = [],
                 UNI_OMEGA: bool = False) -> None:
        r"""
        Parameters
        ----------
        coeff :
            The derivatives of the coefficients.
        order_taylor :
            The order of coeff coefficients Taylor series expansion to
            take into account. (will be set to the length of the coeff
            array if one is provided)
        start_taylor :
            The order of the derivative from which to start the Taylor
            series expansion.
        skip_taylor :
            The order_taylors of the derivative to not consider.
        UNI_OMEGA :
            If True, consider only the center omega for computation.
            Otherwise, considered omega discretization.

        """
        super().__init__()
        self._UNI_OMEGA = UNI_OMEGA
        self._order_taylor: int = order_taylor
        self._start_taylor: int = start_taylor
        self._skip_taylor: List[int] = skip_taylor
        # The attenuation constant -------------------------------------
        self._op: np.ndarray = np.array([])
        self._coeff_op: np.ndarray = np.array([])
        self._coeff: Union[np.ndarray, Callable]
        if (callable(coeff)):
            self._coeff = coeff
        else:
            self._coeff_values = np.asarray(util.make_list(coeff))
            #fct2pickle = lambda omega, order: util.hstack_like(coeff_, omega)
            #self._coeff = CallableContainer(fct2pickle)
            self._coeff = self._hstack_like
            max_order_taylor: int = len(self._coeff_values) - 1
            if (self._order_taylor > max_order_taylor):
                self._order_taylor = max_order_taylor
                warning_message = (
                    "The requested order is higher than the "
                    "provided coefficients, max order of {} will be set.".
                    format(max_order_taylor))
                warnings.warn(warning_message, TaylorOrderWarning)
Exemplo n.º 11
0
def add_2D_subplot(plt_to_add, x_data, y_data, x_label, y_label, x_range,
                   y_range, plot_title, line_label, line_style, line_width,
                   line_color, line_opacity):
    """Plot a 2D graph."""
    x_data_ = np.array([x_data]) if (x_data.ndim < 2) else x_data
    y_data_ = np.array([y_data]) if (y_data.ndim < 2) else y_data
    x_data_ = util.modify_length_ndarray(x_data_, len(y_data_))
    multi_channel = len(y_data_) > 1
    labels_on_plot = line_label is not None
    colors_on_plot = line_color is not None
    if (multi_channel):
        line_label = util.make_list(line_label, len(y_data_))
    for i in range(len(y_data_)):
        if (multi_channel):
            if (labels_on_plot):
                line_label_ = line_label[i] + " (ch.{})".format(i)
            else:
                line_label_ = "channel {}".format(i)
        else:
            line_label_ = line_label
        if (not colors_on_plot):
            line_color = linecolors[add_2D_subplot.counter % len(linecolors)]
            add_2D_subplot.counter += 1
        if (labels_on_plot or multi_channel):
            plt_to_add.plot(x_data_[i],
                            y_data_[i],
                            ls=line_style,
                            lw=line_width,
                            c=line_color,
                            label=line_label_)
        else:
            plt_to_add.plot(x_data_[i],
                            y_data_[i],
                            ls=line_style,
                            lw=line_width,
                            c=line_color)
        plt_to_add.fill_between(x_data_[i],
                                y_data_[i],
                                alpha=line_opacity,
                                facecolor=line_color)
        add_subplot_para(plt_to_add,
                         x_label=x_label,
                         y_label=y_label,
                         x_range=x_range,
                         y_range=y_range,
                         plot_title=plot_title)
        if (labels_on_plot or multi_channel):
            plt_to_add.legend(loc="best")
Exemplo n.º 12
0
    def __init__(self,
                 beta: Optional[Union[List[float], Callable]] = None,
                 order: int = 2,
                 medium: str = cst.DEF_FIBER_MEDIUM,
                 start_taylor: int = 0,
                 skip_taylor: List[int] = []) -> None:
        r"""
        Parameters
        ----------
        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}]`
        order :
            The order of beta coefficients to take into account. (will
            be ignored if beta values are provided - no file)
        medium :
            The medium in which the dispersion is considered.
        start_taylor :
            The order of the derivative from which to start the Taylor
            Series expansion.

        """
        super().__init__()
        self._order: int = order
        self._medium: str = medium
        self._start_taylor: int = start_taylor
        self._skip_taylor: List[int] = skip_taylor
        self._predict: Optional[Callable] = None
        self._beta: Array[float]
        self._class_n: Optional[Callable] = None
        if (beta is not None):
            if (callable(beta)):
                self._predict = beta
            else:
                beta = util.make_list(beta)  # make sure is list
                self._beta = np.asarray(beta).reshape((1, -1))
                self._order = self._beta.shape[1] - 1
        else:
            self._predict = self.calc_beta_coeffs
            self._class_n = Sellmeier(medium)
Exemplo n.º 13
0
    def __init__(self,
                 alpha: Optional[Union[List[float], Callable]] = None,
                 order: int = 1,
                 medium: str = cst.DEF_FIBER_MEDIUM,
                 start_taylor: int = 0,
                 skip_taylor: List[int] = []) -> 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}]`
        order :
            The order of alpha coefficients to take into account. (will
            be ignored if alpha values are provided - no file)
        medium :
            The medium in which the attenuation is considered.
        start_taylor :
            The order of the derivative from which to start the Taylor
            Series expansion.

        """
        super().__init__()
        self._order: int = order
        self._medium: str = medium
        self._start_taylor: int = start_taylor
        self._skip_taylor: List[int] = skip_taylor
        self._predict: Optional[Callable] = None
        self._alpha: Array[float]
        self._future_eq_to_calc_alpha: bool = False
        if (alpha is not None):
            if (callable(alpha)):
                self._predict = alpha
            else:  # alpha is a array of float
                alpha = util.make_list(alpha)  # make sure is list
                self._alpha = np.asarray(alpha).reshape((1, -1))
                self._order = self._alpha.shape[1] - 1
        else:
            self._future_eq_to_calc_alpha = True
Exemplo n.º 14
0
    def __init__(self,
                 re: REFiber,
                 alpha: Optional[List[float]] = None) -> None:
        r"""
        Parameters
        ----------
        re : REFiber
            The rate equations object.
        alpha :
            The attenuation coefficient. :math:`[km^{-1}]`

        """
        super().__init__()
        self._re: REFiber = re
        self._alpha: Array[float]
        if (alpha is None):
            self._alpha = np.zeros(0.0)
        else:
            alpha = util.make_list(alpha)
            self._alpha = np.asarray(alpha)
        self._factor: Array[float]
Exemplo n.º 15
0
def add_2D_subplot(plt_to_add, x_data, y_data, x_label, y_label, x_range,
                   y_range, plot_title, plot_label, plot_linestyle,
                   plot_color, opacity):
    x_data_temp = np.asarray(x_data)
    x_data = np.array([])
    y_data_temp = np.asarray(y_data)
    y_data = np.array([])
    x_data, y_data = util.auto_pad(x_data_temp, y_data_temp)
    multi_channel = len(y_data) > 1
    labels_on_plot = plot_label is not None
    colors_on_plot = plot_color is not None
    if (multi_channel):
        plot_label = util.make_list(plot_label, len(y_data))
    print('in plot', x_data.shape, y_data.shape)
    print(x_data)
    for i in range(len(y_data)):
        if (multi_channel):
            if (labels_on_plot):
                plot_label_temp = plot_label[i] + " (ch.{})".format(i)
            else:
                plot_label_temp = "channel {}".format(i)
        else:
            plot_label_temp = plot_label
        if (not colors_on_plot):
            plot_color = linecolors[add_2D_subplot.counter]
            add_2D_subplot.counter += 1
        if (labels_on_plot or multi_channel):
            plt_to_add.plot(x_data , y_data[i], ls=plot_linestyle,
                            c=plot_color, label=plot_label_temp)
        else:
            plt_to_add.plot(x_data , y_data[i], ls=plot_linestyle,
                            c=plot_color)
        plt_to_add.fill_between(x_data , y_data[i], alpha=opacity,
                                facecolor=plot_color)
        add_subplot_para(plt_to_add, x_label=x_label, y_label=y_label,
                         x_range=x_range, y_range=y_range,
                         plot_title=plot_title)
        if (labels_on_plot or multi_channel):
            plt_to_add.legend(loc = "best")
Exemplo n.º 16
0
    def __init__(self,
                 name: str = default_name,
                 channels: int = 1,
                 center_lambda: List[float] = [cst.DEF_LAMBDA],
                 position: List[float] = [0.5],
                 width: List[float] = [10.0],
                 fwhm: Optional[List[float]] = None,
                 peak_power: List[float] = [1e-3],
                 rep_freq: List[float] = [0.0],
                 offset_nu: List[float] = [0.0],
                 chirp: List[float] = [0.0],
                 init_phi: List[float] = [0.0],
                 noise: Optional[np.ndarray] = None,
                 field_name: str = '',
                 save: bool = False,
                 pre_call_code: str = '',
                 post_call_code: str = '') -> None:
        r"""
        Parameters
        ----------
        name :
            The name of the component.
        channels :
            The number of channels in the field.
        center_lambda :
            The center wavelength of the channels. :math:`[nm]`
        position :
            Relative position of the pulses in the time window.
            :math:`\in [0,1]`
        width :
            Half width of the pulse. :math:`[ps]`
        fwhm :
            Full band width at half maximum. :math:`[ps]`  If fwhm is
            provided, the width will be ignored. If fwhm is not provided
            or set to None, will use the width.
        peak_power :
            Peak power of the pulses. :math:`[W]`
        rep_freq :
            The repetition frequency of the pulse in the time window.
            :math:`[THz]`
        offset_nu :
            The offset frequency. :math:`[THz]`
        chirp :
            The chirp parameter for chirped pulses.
        init_phi :
            The initial phase of the pulses.
        noise :
            The initial noise along the pulses.
        field_name :
            The name of the field.
        save :
            If True, the last wave to enter/exit a port will be saved.
        pre_call_code :
            A string containing code which will be executed prior to
            the call to the function :func:`__call__`. The two
            parameters `input_ports` and `input_fields` are available.
        post_call_code :
            A string containing code which will be executed posterior to
            the call to the function :func:`__call__`. The two
            parameters `output_ports` and `output_fields` are available.

        """
        # Parent constructor -------------------------------------------
        ports_type = [cst.OPTI_OUT]
        super().__init__(name,
                         default_name,
                         ports_type,
                         save,
                         pre_call_code=pre_call_code,
                         post_call_code=post_call_code)
        # Attr types check ---------------------------------------------
        util.check_attr_type(channels, 'channels', int)
        util.check_attr_type(center_lambda, 'center_lambda', float, list)
        util.check_attr_type(position, 'position', float, list)
        util.check_attr_type(width, 'width', float, list)
        util.check_attr_type(fwhm, 'fwhm', float, list, None)
        util.check_attr_type(peak_power, 'peak_power', float, list)
        util.check_attr_type(rep_freq, 'rep_freq', float, list)
        util.check_attr_type(offset_nu, 'offset_nu', float, list)
        util.check_attr_type(chirp, 'chirp', float, list)
        util.check_attr_type(init_phi, 'init_phi', float, list)
        util.check_attr_type(noise, 'noise', None, np.ndarray)
        util.check_attr_type(field_name, 'field_name', str)
        # Attr ---------------------------------------------------------
        self.channels: int = channels
        self.center_lambda: List[float] = util.make_list(
            center_lambda, channels)
        self.position: List[float] = util.make_list(position, channels)
        self.width: List[float] = util.make_list(width, channels)
        self._fwhm: Optional[List[float]]
        self.fwhm = fwhm
        self.peak_power: List[float] = util.make_list(peak_power, channels)
        self.rep_freq: List[float] = util.make_list(rep_freq, channels)
        self.offset_nu: List[float] = util.make_list(offset_nu, channels)
        self.chirp: List[float] = util.make_list(chirp, channels)
        self.init_phi: List[float] = util.make_list(init_phi, channels)
        self.noise: Optional[np.ndarray] = noise
        self.field_name: str = field_name
Exemplo n.º 17
0
    def __init__(self,
                 name: str = default_name,
                 phase_shift: Union[List[float], List[Callable]] = [0.0, 0.0],
                 loss: float = 0.0,
                 extinction: Optional[float] = None,
                 v_pi: Optional[List[float]] = None,
                 v_bias: Optional[List[float]] = None,
                 v_mod: Optional[List[Callable]] = None,
                 save: bool = False,
                 max_nbr_pass: Optional[List[int]] = None,
                 pre_call_code: str = '',
                 post_call_code: str = '') -> None:
        r"""
        Parameters
        ----------
        name :
            The name of the component.
        phase_shift :
            The phase difference induced between the two arms of the MZ.
            Can be a list of callable with time variable. :math:`[ps]`
            (will be ignored if (v_pi and v_bias) or (v_pi and v_mod)
            are provided)
        loss :
            The loss induced by the MZ. :math:`[dB]`
        extinction :
            The extinction ratio. :math:`[dB]`
        v_pi :
            The half-wave voltage. :math:`[V]`
        v_bias :
            The bias voltage. :math:`[V]`
        v_mod :
            The modulation voltage :math:`[V]`. Must be a callable with
            time variable. :math:`[ps]`
        save :
            If True, the last wave to enter/exit a port will be saved.
        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.
        pre_call_code :
            A string containing code which will be executed prior to
            the call to the function :func:`__call__`. The two
            parameters `input_ports` and `input_fields` are available.
        post_call_code :
            A string containing code which will be executed posterior to
            the call to the function :func:`__call__`. The two
            parameters `output_ports` and `output_fields` are available.

        """
        # Parent constructor -------------------------------------------
        ports_type = [cst.ANY_ALL, cst.ANY_ALL]
        super().__init__(name,
                         default_name,
                         ports_type,
                         save,
                         max_nbr_pass=max_nbr_pass,
                         pre_call_code=pre_call_code,
                         post_call_code=post_call_code)
        # Attr types check ---------------------------------------------
        util.check_attr_type(phase_shift, 'phase_shift', float, Callable, list)
        util.check_attr_type(loss, 'loss', float)
        util.check_attr_type(extinction, 'extinction', None, float)
        util.check_attr_type(v_pi, 'v_pi', None, float, list)
        util.check_attr_type(v_bias, 'v_bias', None, float, list)
        util.check_attr_type(v_mod, 'v_mod', None, Callable, list)
        # Attr ---------------------------------------------------------
        self._v_pi: Optional[List[float]]
        self._v_pi = v_pi if v_pi is None else util.make_list(v_pi, 2)
        self._v_bias: Optional[List[float]]
        self._v_bias = v_bias if v_bias is None else util.make_list(v_bias, 2)
        self._v_mod: Optional[List[Callable]]
        self._v_mod = v_mod if v_mod is None else util.make_list(v_mod, 2)
        if (v_pi is not None and (v_bias is not None or v_mod is not None)):
            self._update_phase_shift()
        else:
            self.phase_shift = phase_shift
        self.loss = loss
        self._extinction: Optional[float]
        self.extinction = extinction
        self._divider = IdealDivider(name='nocount',
                                     arms=2,
                                     divide=True,
                                     ratios=[0.5, 0.5])
        # Policy -------------------------------------------------------
        self.add_port_policy(([0], [1], True))
Exemplo n.º 18
0
 def fwhm(self, fwhm: Optional[List[float]]) -> None:
     if (fwhm is None):
         self._fwhm = None
     else:
         self._fwhm = util.make_list(fwhm, self.channels)
Exemplo n.º 19
0
    def __init__(self,
                 solvers: List[AbstractSolver],
                 noise_solvers: List[Optional[AbstractSolver]] = [None],
                 length: float = 1.0,
                 steps: List[int] = [100],
                 step_method: List[str] = [FIXED],
                 solver_order: str = FOLLOWING,
                 stepper_method: List[str] = [FORWARD],
                 solver_sequence: Optional[List[int]] = None,
                 boundary_cond: Optional[AbstractBoundaryConditions] = None,
                 conv_checker: Optional[AbstractConvergenceChecker] = None,
                 save_all: bool = False) -> None:
        r"""
        Parameters
        ----------
        solvers :
            The solvers used to solve the equations.
        nlse_solvers :
            The solvers used to solve the noise equations.
        length :
            The length over which the equation is considered.
            :math:`[km]`
        steps :
            The number of steps used for the computation.
        step_method :
            The method used to update the step size.
        solver_order :
            The order type in which the methods will be computed. (will
            be ignored if solver_sequence is provided)
        stepper_method :
            The method used to converge to solution.
        solver_sequence :
            The sequence in which the methods will be computed.
        boundary_cond : AbstractBoundaryConditions
            The boundaries conditions.
        conv_checker : AbstractConvergenceChecker
            The convergence checker.
        save_all :
            If True, will save all channels of all fields at each space
            step during the equation resolution. The number of step
            recorded depends on the :attr:`memory_storage` attribute
            of :class:`layout.Layout`.

        """
        # Attr types check ---------------------------------------------
        util.check_attr_type(length, 'length', int, float)
        util.check_attr_type(steps, 'steps', int, list)
        util.check_attr_type(step_method, 'step_method', str, list)
        util.check_attr_type(solver_order, 'solver_order', str)
        util.check_attr_type(stepper_method, 'stepper_method', str, list)
        util.check_attr_type(boundary_cond, 'boundary_cond',
                             AbstractBoundaryConditions, None)
        util.check_attr_type(conv_checker, 'conv_checker',
                             AbstractConvergenceChecker, None)
        util.check_attr_type(save_all, 'save_all', bool)
        # Attr ---------------------------------------------------------
        self._solvers: List[AbstractSolver] = util.make_list(solvers)
        self._nbr_solvers: int = len(self._solvers)
        self._noise_solvers: List[Optional[AbstractSolver]]
        self._noise_solvers = util.make_list(noise_solvers, self._nbr_solvers,
                                             None)
        self._eqs: List[SOLVER_CALLABLE_TYPE]
        self._eqs = [self._solvers[i].f for i in range(self._nbr_solvers)]
        self._steps: List[int] = util.make_list(steps, self._nbr_solvers)
        self._length: float = length
        # Stepper method
        stepper_method = util.make_list(stepper_method, self._nbr_solvers)
        self._stepper_method_str: List[str] = []
        self._stepper_method: List[STEPPER_METHOD_TYPE] = []
        for i in range(len(stepper_method)):
            self._stepper_method_str.append(
                util.check_attr_value(stepper_method[i].lower(),
                                      STEPPER_METHODS, FORWARD))
            self._stepper_method.append(
                getattr(
                    self,
                    "_{}_method".format(self._stepper_method_str[i].lower())))
        # Step method
        step_method = util.make_list(step_method, self._nbr_solvers)
        self._step_method_str: List[str] = []
        self._step_method: List[STEP_METHOD_TYPE] = []
        for i in range(len(step_method)):
            self._step_method_str.append(
                util.check_attr_value(step_method[i].lower(), STEP_METHODS,
                                      FIXED))
            self._step_method.append(
                getattr(self,
                        "_{}_step".format(self._step_method_str[i].lower())))
        # Solver order
        solver_order = util.check_attr_value(solver_order.lower(),
                                             SOLVER_ORDERS, FOLLOWING)
        if (solver_sequence is None):
            if (solver_order.lower() == ALTERNATING):
                solver_sequence = [0 for i in range(self._nbr_solvers)]
            if (solver_order.lower() == FOLLOWING):
                solver_sequence = [i for i in range(self._nbr_solvers)]
        else:
            solver_sequence = solver_sequence
        self._solver_seq_ids: List[List[int]] =\
            self._get_seq_ids(solver_sequence)
        self.save_all: bool = save_all
        self._avail_memory: float = 0.
        self._save_step: int = 0
        self._enough_space: bool = False
        self._storage: Storage = Storage()
        self._channels: np.ndarray = np.array([])
        self._noises: np.ndarray = np.array([])
        self._space: np.ndarray = np.array([])
        self._conv_checker: Optional[AbstractConvergenceChecker] = conv_checker
        self._boundary_cond: Optional[
            AbstractBoundaryConditions] = boundary_cond
Exemplo n.º 20
0
    def __init__(self,
                 eqs: List[AbstractEquation],
                 method: List[str] = [cst.DEFAULT_SOLVER],
                 length: float = 1.0,
                 steps: List[int] = [100],
                 step_method: List[str] = [FIXED],
                 solver_order: str = FOLLOWING,
                 stepper_method: List[str] = [FORWARD],
                 solver_sequence: Optional[List[int]] = None,
                 error: float = 0.01,
                 save_all: bool = False) -> None:
        r"""
        Parameters
        ----------
        eqs : list of AbstractEquation
            The equation to solve.
        method :
            The method used to solve the equation.
        length :
            The length over which the equation is considered.
            :math:`[km]`
        steps :
            The number of steps used for the computation.
        step_method :
            The method used to update the step size.
        solver_order :
            The order type in which the methods will be computed. (will
            be ignored if solver_sequence is provided)
        stepper_method :
            The method used to converge to solution.
        solver_sequence :
            The sequence in which the methods will be computed.
        error :
            The error for convergence criterion of stepper resolution.
        save_all :
            If True, will save all channels of all fields at each space
            step during the equation resolution. The number of step
            recorded depends on the :attr:`memory_storage` attribute
            of :class:`layout.Layout`.

        """
        self._eqs: List[AbstractEquation] = util.make_list(eqs)
        self._nbr_solvers: int = len(self._eqs)
        self._methods: List[str] = util.make_list(method, self._nbr_solvers)
        self._steps: List[int] = util.make_list(steps, self._nbr_solvers)
        self._length: float = length
        self._solvers: List[Solver] = [
            Solver(self._eqs[i], self._methods[i])
            for i in range(self._nbr_solvers)
        ]
        stepper_method = util.make_list(stepper_method, self._nbr_solvers)
        self._stepper_method_str = stepper_method
        self._stepper_method = [
            getattr(self, "_{}_method".format(stepper_method[i].lower()))
            for i in range(self._nbr_solvers)
        ]
        step_method = util.make_list(step_method, self._nbr_solvers)
        self._step_method_str = step_method
        self._step_method = [
            getattr(self, "_{}_step".format(step_method[i].lower()))
            for i in range(self._nbr_solvers)
        ]
        self._start_shooting_forward: bool = True
        if (solver_sequence is None):
            if (solver_order.lower() == ALTERNATING):
                solver_sequence = [0 for i in range(self._nbr_solvers)]
            if (solver_order.lower() == FOLLOWING):
                solver_sequence = [i for i in range(self._nbr_solvers)]
        else:
            solver_sequence = solver_sequence
        self._solver_seq_ids: List[List[int]] =\
            self._get_seq_ids(solver_sequence)
        self._error: float = error
        self.save_all: bool = save_all
        self._storage: Storage = Storage()
Exemplo n.º 21
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
Exemplo n.º 22
0
    def __init__(self,
                 name: str = default_name,
                 phase_shift: Union[List[float], List[Callable]] = [0.0, 0.0],
                 loss: float = 0.0,
                 ext_ratio: float = 0.0,
                 v_pi: Optional[List[float]] = None,
                 v_bias: Optional[List[float]] = None,
                 v_mod: Optional[List[Callable]] = None,
                 save: bool = False,
                 max_nbr_pass: Optional[List[int]] = None) -> None:
        r"""
        Parameters
        ----------
        name :
            The name of the component.
        phase_shift :
            The phase difference induced between the two arms of the MZ.
            Can be a list of callable with time variable. :math:`[ps]`
            (will be ignored if (v_pi and v_bias) or (v_pi and v_mod)
            are provided)
        loss :
            The loss induced by the MZ. :math:`[dB]`
        ext_ratio :
            The extinction ratio.
        v_pi :
            The half-wave voltage. :math:`[V]`
        v_bias :
            The bias voltage. :math:`[V]`
        v_mod :
            The modulation voltage :math:`[V]`. Must be a callable with
            time variable. :math:`[ps]`
        save :
            If True, the last wave to enter/exit a port will be saved.
        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.ANY_ALL, cst.ANY_ALL]
        super().__init__(name,
                         default_name,
                         ports_type,
                         save,
                         max_nbr_pass=max_nbr_pass)
        # Attr types check ---------------------------------------------
        util.check_attr_type(phase_shift, 'phase_shift', float, Callable, list)
        util.check_attr_type(loss, 'loss', float)
        util.check_attr_type(ext_ratio, 'ext_ratio', float)
        util.check_attr_type(v_pi, 'v_pi', None, float, list)
        util.check_attr_type(v_bias, 'v_bias', None, float, list)
        util.check_attr_type(v_mod, 'v_mod', None, Callable, list)
        # Attr ---------------------------------------------------------
        if (v_pi is not None and (v_bias is not None or v_mod is not None)):
            pi_ = util.make_list(v_pi, 2)
            bias_ = util.make_list(v_bias, 2) if v_bias is not None\
                        else [0.0, 0.0]
            mod_ = util.make_list(v_mod, 2) if v_mod is not None\
                        else [lambda t: 0.0, lambda t: 0.0]
            phase_shift_ = [
                lambda t: cst.PI * (bias_[0] + mod_[0](t)) / pi_[0],
                lambda t: cst.PI * (bias_[1] + mod_[1](t)) / pi_[1]
            ]
        else:
            phase_shift_ = util.make_list(phase_shift, 2, 0.0)
        # N.B. name='nocount' to avoid inc. default name counter
        self._divider = IdealDivider(name='nocount',
                                     arms=2,
                                     divide=True,
                                     ratios=[0.5, 0.5])
        self._combiner = IdealCombiner(name='nocount',
                                       arms=2,
                                       combine=True,
                                       ratios=[0.5, 0.5])
        self._phasemod_1 = IdealPhaseMod(name='nocount',
                                         phase_shift=phase_shift_[0])
        self._phasemod_2 = IdealPhaseMod(name='nocount',
                                         phase_shift=phase_shift_[1])
        self._amp = IdealAmplifier(name='nocount', gain=-loss)
        # Policy -------------------------------------------------------
        self.add_port_policy(([0], [1], True))
Exemplo n.º 23
0
    def __init__(self,
                 name: str = default_name,
                 channels: int = 1,
                 center_lambda: List[float] = [cst.DEF_LAMBDA],
                 position: List[float] = [0.5],
                 width: List[float] = [10.0],
                 peak_power: List[float] = [1e-3],
                 bit_rate: List[float] = [0.0],
                 offset_nu: List[float] = [0.0],
                 chirp: List[float] = [0.0],
                 init_phi: List[float] = [0.0],
                 save: bool = False) -> None:
        r"""
        Parameters
        ----------
        name :
            The name of the component.
        channels :
            The number of channels in the field.
        center_lambda :
            The center wavelength of the channels. :math:`[nm]`
        position :
            Relative position of the pulses in the time window.
            :math:`\in [0,1]`
        width :
            Half width of the pulse. :math:`[ps]`
        peak_power :
            Peak power of the pulses. :math:`[W]`
        bit_rate :
            Bit rate (repetition rate) of the pulse in the time window.
            :math:`[THz]`
        offset_nu :
            The offset frequency. :math:`[THz]`
        chirp :
            The chirp parameter for chirped pulses.
        init_phi :
            The initial phase of the pulses.
        save :
            If True, the last wave to enter/exit a port will be saved.

        """
        # Parent constructor -------------------------------------------
        ports_type = [cst.OPTI_OUT]
        super().__init__(name, default_name, ports_type, save)
        # Attr types check ---------------------------------------------
        util.check_attr_type(channels, 'channels', int)
        util.check_attr_type(center_lambda, 'center_lambda', float, list)
        util.check_attr_type(position, 'position', float, list)
        util.check_attr_type(width, 'width', float, list)
        util.check_attr_type(peak_power, 'peak_power', float, list)
        util.check_attr_type(bit_rate, 'bit_rate', float, list)
        util.check_attr_type(offset_nu, 'offset_nu', float, list)
        util.check_attr_type(chirp, 'chirp', float, list)
        util.check_attr_type(init_phi, 'init_phi', float, list)
        # Attr ---------------------------------------------------------
        self.channels: int = channels
        self.center_lambda: List[float] = util.make_list(
            center_lambda, channels)
        self.position: List[float] = util.make_list(position, channels)
        self.width: List[float] = util.make_list(width, channels)
        self.peak_power: List[float] = util.make_list(peak_power, channels)
        self.bit_rate: List[float] = util.make_list(bit_rate, channels)
        self.offset_nu: List[float] = util.make_list(offset_nu, channels)
        self.chirp: List[float] = util.make_list(chirp, channels)
        self.init_phi: List[float] = util.make_list(init_phi, channels)
Exemplo n.º 24
0
    def __init__(self, nbr_fibers: int, beta: Optional[Union[List[List[float]],
                                                             Callable]],
                 kappa: Optional[List[List[List[float]]]],
                 sigma_cross: List[List[float]],
                 c2c_spacing: List[List[float]], core_radius: List[float],
                 V: List[float], n_0: List[float], ASYM: bool, COUP: bool,
                 XPM: bool, medium: str) -> None:
        r"""
        Parameters
        ----------
        nbr_fibers :
            The number of fibers in the coupler.
        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]`
        kappa :
            The coupling coefficients. :math:`[km^{-1}]`
        sigma_cross :
            Positive term multiplying the XPM term of the NLSE inbetween
            the fibers.
        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.
        ASYM :
            If True, trigger the asymmetry effects between cores.
        COUP :
            If True, trigger the coupling effects between cores.
        XPM :
            If True, trigger the cross-phase modulation.
        medium :
            The main medium of the fiber.

        """

        super().__init__(nbr_fibers)
        if (beta is not None):
            beta_: Union[List[List[float]], List[List[Callable]]] =\
                util.make_matrix(beta, nbr_fibers, nbr_fibers)
        sigma_cross = util.make_matrix(sigma_cross,
                                       nbr_fibers,
                                       nbr_fibers,
                                       sym=True)
        if (kappa is not None):
            kappa = util.make_tensor(kappa, nbr_fibers, nbr_fibers, 0)
        V = util.make_list(V, nbr_fibers)
        n_0 = util.make_list(n_0, nbr_fibers)
        c2c_spacing = util.make_matrix(c2c_spacing,
                                       nbr_fibers,
                                       nbr_fibers,
                                       sym=True)
        core_radius = util.make_list(core_radius, nbr_fibers)
        for i in range(nbr_fibers):
            for j in range(nbr_fibers):
                if (i != j):
                    if (ASYM):
                        if (beta is not None):
                            self._effects_lin[i][j].append(
                                Asymmetry(beta_01=beta_[i][0],
                                          beta_02=beta_[j][0]))
                        else:
                            self._effects_lin[i][j].append(
                                Asymmetry(medium=medium))
                    if (COUP):
                        if (kappa is not None):
                            self._effects_all[i][j].append(
                                Coupling(kappa[i][j]))
                        else:
                            same_V = sum(V) / len(V) == V[0]
                            same_a = (sum(core_radius) /
                                      len(core_radius) == core_radius[0])
                            same_n_0 = sum(n_0) / len(n_0) == n_0[0]
                            if (not (same_V and same_a and same_n_0)):
                                util.warning_terminal(
                                    "Automatic calculation "
                                    "of coupling coefficient assumes same "
                                    "V, core_radius and n_0 for now, "
                                    "different ones provided, might lead to "
                                    "unrealistic results.")
                            self._effects_all[i][j].append(
                                Coupling(V=V[i],
                                         a=core_radius[i],
                                         d=c2c_spacing[i][j],
                                         n_0=n_0[i]))
                    if (XPM):
                        self._effects_non_lin[i][j].append(
                            Kerr(SPM=False,
                                 XPM=True,
                                 FWM=False,
                                 sigma=sigma_cross[i][j]))
Exemplo n.º 25
0
    def __init__(self, re: REFiber, alpha: Optional[Union[List[float],
                                                          Callable]],
                 alpha_order: int, beta: Optional[Union[List[float],
                                                        Callable]],
                 beta_order: int, gamma: Optional[Union[float, Callable]],
                 gain_order: int, R_0: float, R_L: float,
                 nl_index: Optional[Union[float, Callable]], ATT: bool,
                 DISP: bool, GS: bool, medium: str, dopant: str) -> None:
        r"""
        Parameters
        ----------
        re :
            A fiber rate equation object.
        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)
        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.
        GS :
            If True, trigger the gain saturation.
        medium :
            The main medium of the fiber amplifier.
        dopant :
            The doped medium of the fiber amplifier.

        """
        # keep all methods from NLSE but bypass constructor
        AbstractEquation.__init__(self)  # grand parent constructor
        self._medium: str = medium
        self._dopant: str = dopant
        self._re: REFiber = re
        self._R_L: float = R_L
        self._R_0: float = R_0
        self._delay_time: Array[float]
        self._coprop: bool
        # Effects ------------------------------------------------------
        self._att_ind: int = -1
        self._disp_ind: int = -1
        self._gs_ind: int = -1
        self._gain_ind: int = -1
        self._gain_order: int = gain_order
        self._beta_order: int = beta_order
        if (ATT):
            self._effects_lin.append(Attenuation(alpha, alpha_order))
            self._att_ind = len(self._effects_lin) - 1
        if (DISP):
            self._effects_lin.append(Dispersion(beta, beta_order))
            self._disp_ind = len(self._effects_lin) - 1
        if (GS):
            start_taylor_gain = 1
            self._effects_lin.append(GainSaturation(re, [0.0]))
            self._gs_ind = len(self._effects_lin) - 1
        else:
            start_taylor_gain = 0
        alpha_temp = [0.0 for i in range(self._gain_order + 1)]
        self._effects_lin.append(
            Attenuation(alpha_temp, start_taylor=start_taylor_gain))
        self._gain_ind = len(self._effects_lin) - 1
        # Gamma --------------------------------------------------------
        self._nl_index: Union[float, Callable] = NLIndex(medium=medium) if\
            (nl_index is None) else nl_index
        self._gamma: Array[float]
        self._predict_gamma: Optional[Callable] = None
        self._custom_gamma: bool = False
        if (gamma is not None):
            if (callable(gamma)):
                self._custom_gamma = True
                self._predict_gamma = gamma
            else:
                self._gamma = np.asarray(util.make_list(gamma))
        else:
            self._predict_gamma = NLCoefficient.calc_nl_coefficient
Exemplo n.º 26
0
 def v_pi(self, v_pi: Optional[List[float]]) -> None:
     self._v_pi = util.make_list(v_pi, 2)
     self._update_phase_shift()
Exemplo n.º 27
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
Exemplo n.º 28
0
 def v_bias(self, v_bias: Optional[List[float]]) -> None:
     self._v_bias = util.make_list(v_bias, 2)
     self._update_phase_shift()
Exemplo n.º 29
0
    def __init__(self,
                 name: str,
                 default_name: str,
                 ports_type: List[int],
                 save: bool,
                 wait: bool = False,
                 max_nbr_pass: Optional[List[int]] = None) -> None:
        """
        Parameters
        ----------
        name :
            The name of the component.
        default_name :
            The default name of the component.
        ports_type :
            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 :
            If True, will save each field going through each port. The
            recorded fields can be accessed with the attribute
            :attr:`fields`.
        wait :
            If True, will wait for specified waiting port policy added
            with the function :func:`AbstractComponent.add_wait_policy`.
        max_nbr_pass :
            If not None, 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.

        """
        # Attr type check ----------------------------------------------
        util.check_attr_type(name, 'name', str)
        util.check_attr_type(default_name, 'default_name', str)
        util.check_attr_type(ports_type, 'ports_type', list)
        util.check_attr_type(save, 'save', bool)
        util.check_attr_type(wait, 'wait', bool)
        util.check_attr_type(max_nbr_pass, 'max_nbr_pass', None, list)
        # Nbr of instances and default name management -----------------
        self.inc_nbr_instances()
        self.name: str = name
        if (name == default_name):
            if (self._nbr_instances_with_default_name):
                self.name += ' ' + str(self._nbr_instances_with_default_name)
            self.inc_nbr_instances_with_default_name()
        # Others var ---------------------------------------------------
        self._nbr_ports: int = len(ports_type)
        self.save: bool = save
        self._storages: Storage = []
        self._ports: Port = []
        for i in range(self._nbr_ports):
            self._ports.append(Port(self, i, ports_type[i]))
        self._port_policy: Dict[Tuple[int, ...], Tuple[int, ...]] = {}
        self._wait_policy: List[List[int]] = []
        self._wait: bool = wait
        self._counter_pass: List[int] = [0 for i in range(self._nbr_ports)]
        self._max_nbr_pass: List[int]
        if (max_nbr_pass is None):
            # 999 bcs max default recursion depth with python
            self._max_nbr_pass = [999 for i in range(self._nbr_ports)]
        else:
            self._max_nbr_pass = util.make_list(max_nbr_pass, self._nbr_ports)
Exemplo n.º 30
0
 def v_mod(self, v_mod: Optional[List[Callable]]) -> None:
     self._v_mod = util.make_list(v_mod, 2)
     self._update_phase_shift()