Exemplo n.º 1
0
    def _fit(self, file_path: str, delimiter: str, conv_func: List[Callable],
             conv_factor: List[float]) -> List[Callable]:
        # conv factor first before conv func
        func = []
        data, names = util.read_csv(file_path, delimiter)
        if (not len(data)):
            util.warning_terminal("The csv file provided is either empty or "
                "do not comply with correct synthax.")
        else:
            x = np.asarray(data[0])
            if (len(conv_factor)):
                x *= conv_factor[0]
            if (len(conv_func)):
                x = conv_func[0](x)
            if (len(data) < 1):
                util.warning_terminal("The csv file provided contains only "
                    "one column, must provid at least two for fitting.")
            else:
                for i in range(1, len(data)):
                    y = np.asarray(data[i])
                    if (len(conv_factor) > i):
                        y *= conv_factor[i]
                    if (len(conv_func) > i):
                        y = conv_func[i](y)
                    # Make sure x data are increasing (needed for spl)
                    if (x[0] > x[-1]):
                        func.append(interpolate.splrep(x[::-1], y[::-1]))
                    else:
                        func.append(interpolate.splrep(x, y))

        return func
Exemplo n.º 2
0
    def __init__(self, f: SOLVER_CALLABLE_TYPE, method: Optional[str]) -> None:
        """
        Parameters
        ----------
        f :
            The function to compute.
        method :
            The computation method. Call the __call__ function of the
            equation if None.

        """
        self.name: str
        self._method: METHOD_SOLVER_CALLABLE_TYPE
        if (method is None):  # analytical solution, no need numerical
            self.name = 'f_call'
            self._method = getattr(self, self.name)
        elif (hasattr(self, method.lower())):  # Force to be static method
            self.name = method.lower()
            self._method = getattr(self, self.name)
        else:
            util.warning_terminal("The solver method '{}' does not exist, "
                                  "default solver '{}' is set.".format(
                                      method, self.__class__._default_method))
            self.name = self.__class__._default_method
            self._method = getattr(self, self.__class__._default_method)
        self.f: SOLVER_CALLABLE_TYPE = f
Exemplo n.º 3
0
    def calc_V(omega,
               core_radius=cst.CORE_RADIUS,
               NA=None,
               n_core=None,
               n_clad=None):
        r"""Calculate the V parameter.

        Parameters
        ----------
        omega :
            The angular frequency.  :math:`[rad\cdot ps^{-1}]`
        core_radius :
            The radius of the core. :math:`[\mu m]`
        NA :
            The numerical aperture.
        n_core :
            The refractive index of the core.
        n_clad :
            The refractive index of the cladding.

        Returns
        -------
        :
            Value of the V parameter.

        Notes
        -----
        Considering:

        .. math:: V = k_0 a \text{NA} = \frac{\omega_0}{c} a \text{NA}
                    = \frac{\omega_0}{c} a
                      (n_{co}^2 - n_{cl}^2)^{\frac{1}{2}}

        """
        # Unit conversion
        core_radius *= 1e3  # um -> nm

        if (isinstance(omega, float)):
            res = 0.0
        else:
            res = np.zeros(omega.shape)

        factor = core_radius * omega / cst.LIGHT_SPEED

        if (NA is not None):
            res = factor * NA

        elif ((n_core is not None) and (n_clad is not None)):
            if (isinstance(omega, float)):
                res = factor * math.sqrt(n_core**2 - n_clad**2)
            else:
                res = factor * np.sqrt(np.square(n_core) - np.square(n_clad))
        else:
            util.warning_terminal(
                "Not enough information to calculate the "
                "V parameter, must specified at least the Numerical Aperture "
                "or the refractive index of the core and the cladding. Will "
                "return 0.")

        return res
Exemplo n.º 4
0
    def __init__(self, medium: str = 'sio2', Bs: Optional[List[float]] = None,
                 Cs: Optional[List[float]] = None) -> None:
        r"""
        Parameters
        ----------
        medium :
            The medium in which the wave propagates.
        Bs :
            B coefficients.
        Cs :
            C coefficients.

        """
        super().__init__(medium)
        self._Bs: List[float] = [0.0]
        self._Cs: List[float] = [0.0]
        if (Cs is not None and Bs is not None):
            self._Bs = Bs
            self._Cs = Cs
        elif (self._medium in media):
            self._Bs = coeff_values[self._medium][0]
            self._Cs = coeff_values[self._medium][1]
        else:
            util.warning_terminal("The medium is not recognised or no "
                "coefficients provided in Sellmeier equations, coefficients "
                "set to zero.")
Exemplo n.º 5
0
    def output_ports(self, input_ports: List[int]) -> List[int]:
        """Return a list of the corresponding output port(s) to the
        specified input port(s) depending on all ports in the provided
        list.

        Parameters
        ----------
        input_ports :
            The inputs ports.

        Returns
        -------
        :
            The output ports.

        """
        output_ports: List[int] = []
        if (not self._port_policy):
            util.warning_terminal("No policy for port management for "
                                  "component {}, no fields propagated.".format(
                                      self.name))
        else:
            uni_ports = util.unique(input_ports)
            uni_output_ports = self._port_policy.get(tuple(uni_ports))
            if (uni_output_ports is None):
                util.warning_terminal(
                    "The input ports {} provided for "
                    "component {} do not match any policy, no fields "
                    "propagated.".format(input_ports, self.name))
            else:
                for i in range(len(input_ports)):
                    index = uni_ports.index(input_ports[i])
                    output_ports.append(uni_output_ports[index])

        return output_ports
Exemplo n.º 6
0
    def _get_waiting(self, comp: AbstractComponent,
                     neighbor: AbstractComponent, port: int, field: Field,
                     input_port: int) -> Tuple[List[int], List[Field]]:
        ports: List[int] = []
        fields: List[Field] = []
        if (self._stack_waiting.get(neighbor) is not None):
            # The last field should be the current one, debug: (unitest)
            if (field != self._stack_waiting[neighbor][1][-1]):
                util.warning_terminal("The last field of coprop stack should "
                                      "be the current field.")
            wait_policy = self._stack_wait_policy[neighbor]
            #debug
            if (wait_policy is None):
                util.warning_terminal(
                    "wait_policy shouldn't be None if "
                    "self._stack_waiting.get(neighbor) is not None")
            ports_ = []
            fields_ = []
            for i, elem in enumerate(self._stack_waiting[neighbor][0][:-1]):
                if (elem in wait_policy):
                    ports.append(elem)
                    fields.append(self._stack_waiting[neighbor][1][i])
                else:
                    ports_.append(elem)
                    fields_.append(self._stack_waiting[neighbor][1][i])
            self._stack_waiting[neighbor] = (ports_, fields_)
            # Clear variables
            if (not self._stack_waiting[neighbor][0]):
                self._stack_waiting.pop(neighbor)
            self._stack_wait_policy.pop(neighbor)

        return ports, fields
Exemplo n.º 7
0
    def _del_edge(self, comp_1: AbstractComponent, port_comp_1: int,
                  comp_2: AbstractComponent, port_comp_2: int) -> None:
        """Delete an edge in the Layout.

        Parameters
        ----------
        comp_1 : AbstractComponent
            The first component of the edge.
        port_comp_1 : int
            The port of the first component.
        comp_2 : AbstractComponent
            The second component of the edge.
        port_comp_2 : int
            The port of the second component.

        """
        link = (comp_1.is_linked_to(port_comp_1, comp_2, port_comp_2)
                and comp_2.is_linked_to(port_comp_2, comp_1, port_comp_1))
        link_unidir = (comp_1.is_linked_to(port_comp_1, comp_2, port_comp_2)
                       and comp_2.is_linked_unidir_to(port_comp_2, comp_1))
        # Link suppression ---------------------------------------------
        if (link or link_unidir):
            comp_1.del_port(port_comp_1)
            comp_2.del_port(port_comp_2)
        # Link does not exist ------------------------------------------
        else:
            util.warning_terminal("Can not delete a nonexistent edge from "
                "port {} of component '{}' to port {} of component '{}', "
                "action aborted:"
                .format(port_comp_1, comp_1.name, port_comp_2, comp_2.name))
            comp_1.print_port_state(port_comp_1)
            comp_2.print_port_state(port_comp_2)
Exemplo n.º 8
0
    def extend(self, storage: Storage) -> None:
        check_channels = (self._nbr_channels == storage.nbr_channels)
        check_samples = (self._samples == storage.samples)
        if (check_samples):
            channels = storage.channels
            time = storage.time
            if (not check_channels):
                diff = storage.nbr_channels - self._nbr_channels
                if (diff > 0):
                    to_add = np.zeros(((diff, ) + self.channels[0].shape))
                    self.channels = np.vstack((self.channels, to_add))
                    to_add = np.zeros(((diff, ) + self.time[0].shape))
                    self.time = np.vstack((self.time, to_add))
                    self._nbr_channels = storage.nbr_channels
                else:
                    to_add = np.zeros(((abs(diff), ) + channels[0].shape))
                    channels = np.vstack((channels, to_add))
                    to_add = np.zeros(((abs(diff), ) + time[0].shape))
                    time = np.vstack((time, to_add))
            self.channels = np.hstack((self.channels, channels))
            self.time = np.hstack((self.time, time))
            space_to_add = storage.space[0] + np.sum(self._space)
            self._space = np.hstack((self._space, space_to_add))
        else:
            util.warning_terminal("Storages extension aborted: same number of "
                                  "samples is needed for extension.")

        return self
Exemplo n.º 9
0
    def rk4ip(f: AbstractEquation, waves: Array[cst.NPFT], h: float,
              z: float) -> Array[cst.NPFT]:

        if (len(waves) == 1):
            A = copy.deepcopy(waves[0])
            h_h = 0.5 * h
            A_lin = f.exp_term_lin(waves, 0, h_h)
            waves[0] = f.term_non_lin(waves, 0)
            k_0 = h * f.exp_term_lin(waves, 0, h_h)
            waves[0] = A + 0.5 * k_0
            k_1 = h * f.term_non_lin(waves, 0)
            waves[0] = A + 0.5 * k_1
            k_2 = h * f.term_non_lin(waves, 0)
            waves[0] = A_lin + k_2
            waves[0] = f.exp_term_lin(waves, 0, h_h)
            k_3 = h * f.term_non_lin(waves, 0)
            waves[0] = A_lin + k_0 / 6 + (k_1 + k_2) / 3
            waves[0] = k_3 / 6 + f.exp_term_lin(waves, 0, h_h)
            return waves

        else:
            util.warning_terminal("rk4ip with more than one field "
                                  "currently not supported")

        return waves
Exemplo n.º 10
0
    def add_port_policy(self, *policy: Tuple[List[int], List[int],
                                             bool]) -> None:
        """Append a new policy to automatically designate output port
        depending on the input port.

        Parameters
        ----------
            policy :
                The policy (a, b, flag) assigns input ports in list a
                to output ports in list b. If flag is True, also assign
                input ports of b to output ports of a. If there is -1
                in list b, the field entering at the corresponding
                port in list a will not be transmitted.
                N.B.: if (len(a) < len(b)), pad b with length of a.
                len(a) must be >= len(b)
        """
        for pol in policy:
            # Entry ports list must be same size as exit ports list
            if (len(pol[0]) >= len(pol[1])):
                pol_in = util.permutations(pol[0])
                pol_out = util.permutations(
                    util.pad_with_last_elem(pol[1], len(pol[0])))
                for i in range(len(pol_in)):
                    self._port_policy[tuple(pol_in[i])] = tuple(pol_out[i])
                    if (pol[2]):
                        self._port_policy[tuple(pol_out[i])] = tuple(pol_in[i])
            else:
                util.warning_terminal(
                    "The number of entry ports must be "
                    "equal or greater than the number of exit ports.")
Exemplo n.º 11
0
    def rk4ip_gnlse(f: AbstractEquation, waves: Array[cst.NPFT], h: float,
                    z: float) -> Array[cst.NPFT]:
        if (len(waves) == 1):
            h_h = 0.5 * h
            A = copy.deepcopy(waves[0])
            exp_op_lin = f.exp_op_lin(waves, 0, h_h)
            #if (Solver.rk4ip_gnlse.first_rk4ip_gnlse_iter):
            A_lin = exp_op_lin * FFT.fft(A)
            #    Solver.rk4ip_gnlse.first_rk4ip_gnlse_iter = False
            #else:
            #    A_lin = exp_op_lin * Solver.rk4ip_gnlse.fft_A_next
            k_0 = h * exp_op_lin * f.op_non_lin_rk4ip(waves, 0)
            waves[0] = FFT.ifft(A_lin + k_0 / 2)
            k_1 = h * f.op_non_lin_rk4ip(waves, 0)
            waves[0] = FFT.ifft(A_lin + k_1 / 2)
            k_2 = h * f.op_non_lin_rk4ip(waves, 0)
            waves[0] = FFT.ifft(exp_op_lin * (A_lin + k_0 / 2))
            k_3 = h * f.op_non_lin_rk4ip(waves, 0)

            #Solver.rk4ip_gnlse.fft_A_next = k_3/6 + (exp_op_lin
            #                                * (A_lin + k_0/6 + (k_1+k_2)/3))
            waves[0] = FFT.ifft(k_3 / 6 + (exp_op_lin * (A_lin + k_0 / 6 +
                                                         (k_1 + k_2) / 3)))

            return waves

        else:
            util.warning_terminal("rk4ip with more than two fields "
                                  "currently not supported")

        return waves
Exemplo n.º 12
0
    def __setitem__(self, key: int, channel: Array[cst.NPFT, 1, ...]) -> None:

        if (len(channel) == len(self._channels[key])):
            self._channels[key] = channel.astype(cst.NPFT)
        else:
            util.warning_terminal("All channels must have the same dimension, "
                                  "can not change channel.")
Exemplo n.º 13
0
    def __call__(self, domain: Domain) -> Tuple[List[int], List[Field]]:

        output_ports: List[int] = []
        output_fields: List[Field] = []
        field = Field(domain, cst.OPTI, self.field_name)
        # Check offset -------------------------------------------------
        for i in range(len(self.offset_nu)):
            if (abs(self.offset_nu[i]) > domain.nu_window):
                self.offset_nu[i] = 0.0
                util.warning_terminal(
                    "The offset of channel {} in component "
                    "{} is bigger than half the frequency window, offset will "
                    "be ignored.".format(str(i), self.name))
        # Field initialization -----------------------------------------
        if (self.energy):
            peak_power: List[float] = []
            time_window = domain.time_window * 1e-12  # ps -> s
            for i in range(len(self.energy)):
                peak_power.append(self.energy[i] / time_window)
        else:
            peak_power = self.peak_power
        rep_freq = np.nan
        for i in range(self.channels):  # Nbr of channels
            res = np.zeros(domain.time.shape, dtype=cst.NPFT)
            phi = (self.init_phi[i] -
                   Domain.nu_to_omega(self.offset_nu[i]) * domain.time)
            res += math.sqrt(peak_power[i]) * np.exp(1j * phi)
            field.add_channel(res,
                              Domain.lambda_to_omega(self.center_lambda[i]),
                              rep_freq)

        output_fields.append(field)
        output_ports.append(0)

        return output_ports, output_fields
Exemplo n.º 14
0
    def __call__(self, domain: Domain, ports: List[int],
                 fields: List[Field]) -> Tuple[List[int], List[Field]]:
        output_ports: List[int] = []
        output_fields: List[Field] = []
        # Check if the fields are of same types ------------------------
        compatible = True
        for i in range(1, len(fields)):
            if (fields[i].type != fields[i - 1].type):
                compatible = False
                util.warning_terminal("Fields of different types can not be "
                                      "combined.")
        # Combine the wave in list fields ------------------------------
        if (compatible):
            if (self._combine):
                fields[0] *= math.sqrt(self._ratios[ports[0]])
                for i in range(1, len(fields)):
                    ratio = math.sqrt(self._ratios[ports[i]])
                    fields[0].add(fields[i] *
                                  math.sqrt(self._ratios[ports[i]]))
                for i in range(len(fields) - 1, 0, -1):
                    del fields[i]

                return self.output_ports([ports[0]]), [fields[0]]
            else:
                for i in range(len(fields)):
                    output_fields.append(fields[i] *
                                         math.sqrt(self._ratios[ports[i]]))

        return self.output_ports(ports), output_fields
Exemplo n.º 15
0
    def __init__(self,
                 SPM: bool = False,
                 XPM: bool = False,
                 FWM: bool = False,
                 sigma: float = cst.XPM_COEFF) -> None:
        r"""
        Parameters
        ----------
        SPM :
            If True, trigger the self-phase modulation.
        XPM :
            If True, trigger the cross-phase modulation.
        FWM :
            If True, trigger the Four-Wave mixing.
        sigma :
            Positive term multiplying the XPM term.

        """
        super().__init__()
        self._SPM: bool = SPM
        self._XPM: bool = XPM
        self._FWM: bool = FWM
        if (self._FWM):
            util.warning_terminal("FWM effect currently not taken into"
                                  "account.")
        self._sigma: float = sigma
Exemplo n.º 16
0
    def newton_raphson(func, z, h, error=1e-6, max_iter=1e6):
        eval = func(z)
        if (not isinstance(z, np.ndarray)):
            root_0 = 0.
            root_1 = z
            i = 0
            while (not i or abs(root_1 - root_0) > error and i < max_iter):
                eval = func(root_1)
                jacob = Jacobian.calc_jacobian(func, root_1, h)
                jacob_inv = 1 / jacob
                root_0 = root_1
                root_1 = root_1 - jacob_inv * eval
                i += 1
        else:
            if (len(z) != len(eval)):
                util.warning_terminal(
                    "The number of variables and vector "
                    "components must be equal in order to calculate "
                    "determinant, return zeros.")

                return np.zeros_like(z)
            else:
                root_0 = np.zeros_like(z)
                root_1 = z
                i = 0
                while (not i or np.linalg.norm(root_1 - root_0) > error
                       and i < max_iter):
                    eval = func(root_1)
                    jacob = Jacobian.calc_jacobian(func, z, h)
                    jacob_inv = np.linalg.inv(jacob)
                    root_0 = root_1
                    root_1 = root_1 - np.matmul(jacob_inv, eval)
                    i += 1

        return root_1
Exemplo n.º 17
0
    def _del_edge(self, port_1: Port, port_2: Port) -> None:
        """Delete an edge in the Layout.

        Parameters
        ----------
        port_1 : Port
            The first port of the edge.
        port_2 : Port
            The second port of the edge.

        """
        link = (port_1.is_linked_to(port_2) and port_2.is_linked_to(port_1))
        # Link suppression ---------------------------------------------
        if (link):
            port_1.reset()
            port_2.reset()
        # Link does not exist ------------------------------------------
        else:
            util.warning_terminal(
                "Can not delete a nonexistent edge from "
                "port {} of component '{}' to port {} of component '{}', "
                "action aborted:".format(port_1.port, port_1.comp.name,
                                         port_2.port, port_2.comp.name))
            print(port_1)
            print(port_2)
Exemplo n.º 18
0
    def __call__(self, domain: Domain) -> Tuple[List[int], List[Field]]:

        output_ports: List[int] = []
        output_fields: List[Field] = []
        field = Field(domain, cst.OPTI)
        # Bit rate initialization --------------------------------------
        nbr_pulses = []
        for i in range(self.channels):
            if (self.bit_rate[i]):
                nbr_temp = math.floor(domain.time_window * self.bit_rate[i])
                if (nbr_temp):
                    nbr_pulses.append(nbr_temp)
                else:
                    util.warning_terminal(
                        "In component {}: the time window "
                        "is too thin for the bit rate specified, bit rate "
                        "will be ignored".format(self.name))
                    nbr_pulses.append(1)
            else:
                nbr_pulses.append(1)

        rel_pos = []
        for i in range(self.channels):
            pos_step = 1 / nbr_pulses[i]
            if (nbr_pulses[i] % 2):  # Odd
                dist_from_center = nbr_pulses[i] // 2 * pos_step
            else:
                dist_from_center = (nbr_pulses[i] // 2 -
                                    1) * pos_step + pos_step / 2
            rel_pos.append(
                np.linspace(self.position[i] - dist_from_center,
                            self.position[i] + dist_from_center,
                            num=nbr_pulses[i]))
        # Check offset -------------------------------------------------
        for i in range(len(self.offset_nu)):
            if (abs(self.offset_nu[i]) > domain.nu_window):
                self.offset_nu[i] = 0.0
                util.warning_terminal(
                    "The offset of channel {} in component "
                    "{} is bigger than half the frequency window, offset will "
                    "be ignored.".format(str(i), self.name))
        # Field initialization -----------------------------------------
        for i in range(self.channels):  # Nbr of channels
            res = np.zeros(domain.time.shape, dtype=cst.NPFT)
            for j in range(len(rel_pos[i])):
                norm_time = domain.get_shift_time(
                    rel_pos[i][j]) / self.width[i]
                var_time = np.power(norm_time, 2)
                phi = (self.init_phi[i] -
                       Domain.nu_to_omega(self.offset_nu[i]) * domain.time -
                       0.5 * self.chirp[i] * var_time)
                res += (math.sqrt(self.peak_power[i]) / np.cosh(norm_time) *
                        np.exp(1j * phi))
            field.append(res, Domain.lambda_to_omega(self.center_lambda[i]))

        output_fields.append(field)
        output_ports.append(0)

        return output_ports, output_fields
Exemplo n.º 19
0
    def calc_cross_section(omega, dopant ="Yb", predict=None,
                           center_omega=None, N_0=None, N_1=None, T=None):
        r"""Calculate the emission cross section. There is no analytical
        formula for the emission cross section. Calculate first the
        absorption cross sections with the fitting formula from ref.
        [5]_ and then use the McCumber relations to deduce the emission
        cross sections.

        Parameters
        ----------
        omega :
            The angular frequency.  :math:`[rad\cdot ps^{-1}]`
        dopant :
            The type of the doped medium.
        predict :
            A callable object to predict the cross sections.
            The variable must be the wavelength. :math:`[nm]`
        center_omega :
            The center angular frequency.  :math:`[rad\cdot ps^{-1}]`
        N_0 :
            The population in ground state. :math:`[nm^{-3}]`
        N_1 :
            The population in the excited state. :math:`[nm^{-3}]`
        T :
            The temperature. :math:`[K]`

        Returns
        -------
        :
            Value of the emission cross section. :math:`[nm^2]`

        References
        ----------
        .. [5] Valley, G.C., 2001. Modeling cladding-pumped Er/Yb fiber
               amplifiers. Optical Fiber Technology, 7(1), pp.21-44.

        """

        if (isinstance(omega, float)):
            res = 0.0
        else:
            res = np.zeros_like(omega)
        Lambda = Domain.omega_to_lambda(omega)
        if (predict is None):
            if (N_0 is not None and N_1 is not None and T is not None
                    and center_omega is not None):
                sigma_a = Absorption.calc_cross_section(omega, dopant)
                res = McCumber.calc_cross_section_emission(sigma_a, omega,
                                                           center_omega, N_0,
                                                           N_1, T)
            else:
                util.warning_terminal("Not enough information to calculate "
                    "the value of the emission cross sections, will return "
                    "null values.")

        else:   # Interpolate the data from csv file with scipy fct
            res = predict(Lambda)[0]    # Take only zeroth deriv.

        return res
Exemplo n.º 20
0
    def _fixed_step(self,
                    waves: Array[cst.NPFT],
                    solvers: List[Solver],
                    steps: int,
                    forward: bool = True,
                    start: Optional[int] = None) -> Array[cst.NPFT]:
        # Saving management --------------------------------------------
        enough_space: bool
        if (self.save_all):
            if (self._max_nbr_steps):
                enough_space = True
                # N.B. -1 when modulo is zero
                save_step = max(1, int(steps / (self._max_nbr_steps - 1)) - 1)
                nbr_steps = (steps // save_step)
                nbr_steps = (nbr_steps + 1) if save_step != 1 else nbr_steps
            else:
                enough_space = False
                nbr_steps = 2
                util.warning_terminal("Not enough space for storage.")
            size_storage = (waves.shape[0], nbr_steps, waves.shape[1])
            self._channels = np.zeros(size_storage, dtype=cst.NPFT)
            self._space = np.zeros(0)
        # Computation --------------------------------------------------
        zs, h = np.linspace(0.0, self._length, steps + 1, True, True)
        zs = zs[:-1]

        # Need to make it storage dependent here
        if (start is not None and self.save_all and enough_space):
            if (start > 0):
                for i in range(start):
                    for j in range(len(waves)):
                        self._channels[j][i] = waves[j]
                    self._space = np.append(self._space, zs[i])
            if (start < -1):
                for i in range(1, abs(start)):
                    for j in range(len(waves)):
                        self._channels[j][-i] = waves[j]
                    self._space = np.append(self._space, zs[-i])

        if (forward):
            iter_method = 1
            stop = len(zs)
            start = 0 if start is None else start
        else:
            iter_method = -1
            stop = -1
            start = len(zs) - 1 if start is None else len(zs) + start

        for i in range(start, stop, iter_method):
            for id in range(len(solvers)):
                waves = solvers[id](waves, h, zs[i])
            if (self.save_all and enough_space and not i % save_step):
                for j in range(len(waves)):
                    self._channels[j][int(i / save_step)] = waves[j]
                self._space = np.append(self._space, zs[i])

        return waves
Exemplo n.º 21
0
    def _respect_port_valid(self, comp: AbstractComponent,
                            neighbor: AbstractComponent, port: int,
                            field: Field, input_port: int) -> bool:
        """Check if type of field correspond to type of port."""
        flag = neighbor.is_port_type_valid(input_port, field)
        if (not flag):
            util.warning_terminal("Wrong field type to enter port {} "
                "of component {}, field will be ignored."
                .format(input_port, neighbor.name), '')

        return flag
Exemplo n.º 22
0
    def _respect_port_in(self, comp: AbstractComponent,
                         neighbor: AbstractComponent, port: int, field: Field,
                         input_port: int) -> bool:
        """Check if the port allows an input."""
        flag = neighbor.is_port_type_in(input_port)
        if (not flag):
            util.warning_terminal( "Port {} of component {} does not "
                "accept input, field will be ignored."
                .format(input_port, neighbor.name), '')

        return flag
Exemplo n.º 23
0
    def is_port_valid(self, port_nbr: int) -> bool:

        if (0 <= port_nbr < self._nbr_ports):

            return True
        else:
            util.warning_terminal("Port {} out of range, component '{}' have "
                                  "only {} port(s).".format(
                                      port_nbr, self.name, self._nbr_ports))

            return False
Exemplo n.º 24
0
 def _propagate(self, comp: AbstractComponent, output_ports: List[int],
                output_fields: List[Field]) -> None:
     self._update_constraints(comp, output_ports, output_fields)
     # Debug
     if (len(output_ports) != len(output_fields)):
         util.warning_terminal("The length of the output_ports list and "
                               "output_fields list must be equal.")
     # Propagate
     for i in range(len(output_ports)):
         if (output_ports[i] != -1):  # Explicit no propag. port policy
             self._init_propagation(comp, output_ports[i], output_fields[i])
Exemplo n.º 25
0
    def __init__(
        self,
        dopant: str = cst.DEF_FIBER_DOPANT,
        medium: str = cst.DEF_FIBER_DOPANT,
        stark_energies: STARK_ENERGIES_TYPE = ([], [])
    ) -> None:
        """
        Parameters
        ----------
        dopant :
            The doping medium.
        medium :
            The fiber medium.
        stark_energies :
            The stark energies of the first level and the second level.
            The first element of the tuple is a list with all stark
            energies of the first level and the second element of the
            tuple is a list with all stark energies of the second level.
            :math:`[cm^{-1}]` (dopant and medium will be ignored if
            stark_energies are provided)

        """
        self._dopant: str = util.check_attr_value(dopant.lower(), DOPANT,
                                                  cst.DEF_FIBER_DOPANT)
        self._medium: str = util.check_attr_value(medium.lower(),
                                                  MEDIA[self._dopant],
                                                  cst.DEF_FIBER_MEDIUM)
        self._stark_energies: STARK_ENERGIES_TYPE = ([], [])
        if (stark_energies != ([], [])):
            self._stark_energies = stark_energies
        else:
            data = STARK.get(self._dopant)
            if (data is not None):
                stark = data.get(self._medium)
                if (stark is not None):
                    self._stark_energies = stark
                else:
                    util.warning_terminal(
                        "The specify medium {} for the "
                        "dopant {} for Mccumber relations is not valid.".
                        format(self._medium, self._dopant))
                    stark_ = data.get(cst.DEF_FIBER_MEDIUM)
                    if (stark_ is not None):  # Should be obvious (for typing)
                        self._stark_energies = stark_
            else:
                util.warning_terminal(
                    "The specify dopant medium {} for "
                    "Mccumber relations is not valid.".format(self._dopant))
                data_ = STARK.get(cst.DEF_FIBER_DOPANT)
                if (data_ is not None):  # Should be obvious (for typing)
                    stark_ = data_.get(cst.DEF_FIBER_MEDIUM)
                    if (stark_ is not None):  # Same, it is obvious
                        self._stark_energies = stark_
Exemplo n.º 26
0
 def h_R(self) -> Array[float]:
     if (self._h_R is None):
         if (self._time is None):
             util.warning_terminal("Must specified time array to"
                                   "calculate the Raman response function")
         else:
             self._h_R = self.calc_h_R(self._time, self._tau_1, self._tau_2,
                                       self._tau_b, self._f_a, self._f_b,
                                       self._f_c)
             # Save fft of h_R bcs might be reused and not change
             self._fft_h_R = FFT.fft(self._h_R)
     return self._h_R
Exemplo n.º 27
0
    def S(self) -> Array[float]:
        if (self._S is not None):

            return self._S
        else:
            if (self._omega is None):
                util.warning_terminal("Must specified the center omega "
                    "to calculate the self steepening coefficient, has been "
                    "evaluated at zero.")

                return np.zeros(self._center_omega.shape)
            else:

                return 1.0 / self._center_omega
Exemplo n.º 28
0
    def _shooting_method(self, waves: Array[cst.NPFT], solvers: List[Solver],
                         eqs: List[AbstractEquation], steps: int,
                         step_method: STEP_METHOD_TYPE) -> Array[cst.NPFT]:

        # N.B.: take last equation to get criterion by defaults
        #       -> need to handle different cases that might pop up

        def apply_ic(eqs, waves_init, end):

            res = np.zeros_like(waves_init)
            for eq in eqs:
                res = eq.initial_condition(waves_init, end)

            return res

        error_bound = self._error
        # First iteration for co-prop or counter prop scheme
        if (self._start_shooting_forward):
            waves_f = apply_ic(eqs, waves, False)
            waves_f = step_method(waves_f, solvers, steps, True, 1)
        else:
            waves_b = apply_ic(eqs, waves, True)
            waves_b = step_method(waves_b, solvers, steps, False, -2)
            waves_f = apply_ic(eqs, waves, False)
            waves_f = step_method(waves_f, solvers, steps, True, 1)
        # Start loop till convergence criterion is met
        cached_criterion = 0.0
        error = error_bound * 1e10
        while (error > error_bound):
            waves_f_back_up = waves_f
            waves_b = apply_ic(eqs, waves_f, True)
            waves_b = step_method(waves_b, solvers, steps, False, -2)
            waves_f = apply_ic(eqs, waves_b, False)
            waves_f = step_method(waves_f, solvers, steps, True, 1)
            new_cached_criterion = eqs[-1].get_criterion(waves_f, waves_b)
            old_error = error
            error = abs(cached_criterion - new_cached_criterion)
            util.print_terminal(
                "Shooting method is running and got error = {}".format(error),
                '')
            cached_criterion = new_cached_criterion
            if (old_error < error):
                util.warning_terminal(
                    "Shooting method stopped before "
                    "reaching error bound value as error is increasing.")
                error = 0.0
                waves_f = waves_f_back_up

        return waves_f
Exemplo n.º 29
0
    def _respect_max_pass(self, comp: AbstractComponent,
                          neighbor: AbstractComponent, port: int, field: Field,
                          input_port: int) -> bool:
        """Check if the number of time a field can pass by input_port of
        component neighbor is not overpassed.
        """
        neighbor.inc_counter_pass(input_port)
        flag = neighbor.is_counter_below_max_pass(input_port)
        if (not flag):
            util.warning_terminal(
                "Max number of times a field can go through "
                "port {} of component '{}' has been reached, field will be "
                "ignored.".format(input_port, neighbor.name), '')

        return flag
Exemplo n.º 30
0
    def _get_coprop(self, comp: AbstractComponent, neighbor: AbstractComponent,
                    port: int, field: Field,
                    input_port: int) -> Tuple[List[int], List[Field]]:
        ports: List[int] = []
        fields: List[Field] = []
        if (self._stack_coprop.get((comp, port)) is not None):
            # The last field should be the current one, debug: (unitest)
            if (field != self._stack_coprop[(comp, port)][0][-1]):
                util.warning_terminal("The last field of coprop stack should "
                                      "be the current field.")
            fields = self._stack_coprop[(comp, port)][0][:-1]
            ports = [input_port for i in range(len(fields))]
            self._stack_coprop.pop((comp, port))

        return ports, fields