Source codes — beampy 0.0.1.4 documentation

# Source codes

## beampy.bpm

    """
    The bpm module contain the Bpm class used to simulate the light propagation -
    within low refractive index variation
    and small angle (paraxial approximation) -
    using the Beam Propagation Method.

    This module was done by Jonathan Peltier during a master
    university course from the PAIP master of the université de Lorraine,
    under the directive of Pr. Nicolas Fressengeas.

    The bpm codes are mainly based on a compilation of MatLab codes initialy
    developed by Régis Grasser during his PhD thesis[2],
    and later modified at the FEMTO-ST institute of the Université de
    Franche-Comté and at the LMOPS laboratory [3] of the
    Université de Lorraine.

    [1] K. Okamoto, in Fundamentals of Optical Waveguides,
    2nd ed., edited by K. Okamoto (Academic, Burlington, 2006), pp. 329–397.

    [2] "Generation et propagation de reseaux periodiques de solitons spatiaux
    dans un milieu de kerr massif" PhD thesis, université de Franche-Comté 1998.

    [3] H. Oukraou et. al., Broadband photonic transport between waveguides by
    adiabatic elimination Phys. Rev. A, 97 023811 (2018).
    """

    from math import pi, ceil, radians, sqrt, log, sin, cos, acos, asin, exp
    from scipy import special
    from numpy.fft import fft, ifft, fftshift
    import numpy as np

    import matplotlib.pyplot as plt
    from matplotlib.patches import Polygon
    import time

    class Bpm():
        """
        The Bpm class is used to simulate light propagation -
        within small refractive index variation guides
        and small angle of propagation (paraxial) -
        using the Beam Propagation Method.

        Parameters
        ----------
        width : float
            Guide width defined as the diameter (µm) at 1/e^2 intensity.
        no : float
            Refractive index of the cladding.
        delta_no : float
            Difference of refractive index between the core and the cladding.
        length_z : float
            Size of the compute window over z (µm).
        dist_z : float
            Step over z (µm)
        nbr_z_disp : int
            Number of points to display over z.
        length_x : float
            Size of the compute window over x (µm).
        dist_x : float
            Step over x (µm)
        """

        def __init__(self, width, no, delta_no,
                     length_z, dist_z, nbr_z_disp,
                     length_x, dist_x):
            """
            The Bpm class is used to simulate light propagation -
            within small refractive index variation guides
            and small angle of propagation (paraxial) -
            using the Beam Propagation Method.

            Parameters
            ----------
            width : float
                Guide width defined as the diameter (µm) at 1/e^2 intensity.
            no : float
                Refractive index of the cladding
            delta_no : float
                Difference of refractive index between the core and the cladding.
            length_z : float
                Size of the compute window over z (µm).
            dist_z : float
                Step over z (µm).
            nbr_z_disp : int
                Number of points to display over z.
            length_x : float
                Size of the compute window over x (µm).
            dist_x : float
                Step over x (µm).
            """
            self.width = width
            self.no = no
            self.delta_no = delta_no
            self.length_z = length_z
            self.dist_z = dist_z
            self.nbr_z_disp = nbr_z_disp
            self.dist_x = dist_x
            self.length_x = length_x

            if delta_no > no/10:
                print("Careful: index variation is too high:")
                print(delta_no, ">", no, "/ 10")

        def create_x_z(self):
            """
            Create the x, z array and ajust the resolution variables.

            Returns
            -------
            length_z : float
                Corrected value due to nbr_z being an int.
            nbr_z : int
                Number of points computed over z.
            nbr_z_disp : int
                Corrected value due to pas being an int.
            length_x : float
                Corrected value due to nbr_x being an int.
            nbr_x : int
                Number of point over x (µm).
            x : array
                x values between [-length_x/2, length_x/2-dist_x] center on 0.

            Notes
            -----
            This method creates the following variables within the class
            :class:`Bpm`:

            - pas : Interval of computed points between each displayed points.
            """
            assert self.nbr_z_disp > 0

            self.nbr_z = ceil(self.length_z / self.dist_z)
            self.length_z = self.nbr_z * self.dist_z
            self.pas = ceil(self.length_z / (self.nbr_z_disp * self.dist_z))
            self.nbr_z_disp = ceil(self.length_z / (self.pas * self.dist_z))
            self.nbr_z_disp += 1  # add 1 for the initial field
            self.nbr_z += 1  # add 1 for the initial field
            self.nbr_x = ceil(self.length_x / self.dist_x)  # nbr points over x

            # check if even number
            if self.nbr_x % 2 != 0:
                self.nbr_x += 1

            # check if multiple of 8: speeds up execution
            # (was also needed for a obsolete feature)
            for _ in range(3):
                if self.nbr_x % 8 != 0:
                    self.nbr_x += 2
                else:
                    break

            self.length_x = self.nbr_x * self.dist_x
            self.x = np.linspace(-self.length_x/2,
                                 self.length_x/2 - self.dist_x,
                                 self.nbr_x)

            return [self.length_z, self.nbr_z, self.nbr_z_disp-1,
                    self.length_x, self.nbr_x, self.x]

        # Guides #

        def squared_guide(self):
            """
            A lambda function than returns a centered rectangular shape.

            return 1 if :math:`x >= -width/2` and :math:`x <= width/2`
            else return 0.

            Notes
            -----
            This methods uses the width variable defined in :class:`Bpm`.
            """
            return lambda t: (t >= -self.width/2) & (t <= self.width/2)

        def gauss_guide(self, gauss_pow):
            """
            A lambda function than return a centered super-Gaussian shape.

            :math:`e^{-(x/w)^{2P}}`

            The waist is defined as width/2 and correspond to the 1/e
            relative value.

            See :func:`.example_guides_x` for more details.

            Parameters
            ----------
            gauss_pow : int
                Index of the super-gaussian guide with 1 being a regural gaussian
                guide and 4 being the conventionnal super-gaussian guide used to
                describe realistic guides.
                See on en.wikipedia.org/wiki/Gaussian_function
                #Higher-order_Gaussian_or_super-Gaussian_function

            Notes
            -----
            This methods uses the width variable defined in :class:`Bpm`.
            """
            if self.width == 0:
                return lambda t: 0
            w = self.width / 2  # want diameter at 1/e =width so 2*w=witdh
            return lambda t: np.exp(-(t / w)**(2*gauss_pow))

        def create_guides(self, shape, nbr_p, p, offset_guide=0):
            """
            Create an array of guides over x using peaks positions and for a given
            shape.

            Parameters
            ----------
            shape : method
                :meth:`squared_guide`, :meth:`gauss_guide` or any lambda function
                that takes one argument and return the relative refractive index
                for the input position.
            nbr_p : int
                Number of guides.
            p : float
                Distance between two guides center (µm).
            offset_guide : float, optional
                Guide offset from the center (µm). 0 by default.

            Returns
            -------
            peaks : array-like
                Central position of each guide [guide,z].
            dn : array-like
                Difference of reefractive index [z,x].

            Notes
            -----
            This methods uses the following variables defined in :class:`Bpm`:
            nbr_z, nbr_x, x, dist_x, delta_no.
            """
            self.peaks = np.zeros((nbr_p, self.nbr_z))
            self.dn = np.zeros((self.nbr_z, self.nbr_x))
            dn_z = np.zeros(self.nbr_x)

            peaks_z = (p*np.linspace(-nbr_p/2, nbr_p/2-1, nbr_p)
                       + p/2
                       + offset_guide)
            dn_fix = shape(self.x)  # guide shape center on 0

            # Sum each identical guide with an offset defined by peaks_z
            for i in range(nbr_p):
                dn_z += np.roll(dn_fix, int(round(peaks_z[i] / self.dist_x)))

            # only necessary because this program can have curved guides
            for i in range(self.nbr_z):
                self.dn[i, :] = dn_z
                self.peaks[:, i] = peaks_z

            self.dn = self.dn * self.delta_no  # give a value to the shape
            return [self.peaks, self.dn]

        def create_curved_guides(self, shape, curve, half_delay,
                                 distance_factor, offset_guide=0):
            """
            Create two curved guides and one linear guide on the center (STIRAP).

            The central positions over x and z are defined as follow:

            Left guide: :math:`x_0-p_{min}-curve(z-length\_z/2-half\_delay)^2`

            Right guide: :math:`x_0+p_{min}+curve(z-length\_z/2+half\_delay)^2`

            Central guide: :math:`x_0`

            Parameters
            ----------
            shape : method
                :meth:`square` or :meth:`gauss`
            curve : float
                curvature factor in :math:`10^{-8} µm^{-2}`.
            half_delay : float
                Half distance over z in µm bewteen the two external guides where
                they are the closest.
                In other words, the distance from the center and the minimum of one
                of the curved guides over z.
            distance_factor : float
                Factor between the guide width and the minimal distance between the
                two guides =p_min/width.
                If distance_factor=1, the curved guides will touch the central
                guide (p_min=width).
            offset_guide : float, optional
                Guide offset from the center (µm). 0 by default.

            Returns
            -------
            peaks : array
                Central position of each guide as peaks[guide,z].
            dn : array
                Difference of reefractive index as dn[z,x].

            Notes
            -----
            This methods uses the following variables defined in :class:`Bpm`:
            length_z, nbr_z, width, nbr_x, x, dist_x, delta_no.
            """
            # all points over z
            z = np.linspace(0, self.length_z, self.nbr_z)

            # left curved guide
            sa = (- offset_guide
                  + curve*(z - self.length_z/2 - half_delay)**2
                  + self.width*distance_factor)

            # right curved guide
            sb = (offset_guide
                  + curve*(z - self.length_z/2 + half_delay)**2
                  + self.width*distance_factor)

            self.peaks = np.array([-sa,
                                   np.array([offset_guide] * self.nbr_z),
                                   sb])

            self.dn = np.zeros((self.nbr_z, self.nbr_x))
            dn_fix = shape(self.x)   # guide shape center on 0

            for i in range(self.nbr_z):
                self.dn[i, :] = np.roll(dn_fix, int(round(-sa[i] / self.dist_x))) \
                    + np.roll(dn_fix, int(round(offset_guide / self.dist_x))) \
                    + np.roll(dn_fix, int(round(sb[i] / self.dist_x)))

            self.dn = self.dn * self.delta_no  # give a value to the shape
            return [self.peaks, self.dn]

        # Light #

        def gauss_light(self, fwhm, offset_light=0):
            """
            Create a gaussien beam in amplitude.

            :math:`E = e^{-((x-x_0)/w)^{2P}}`

            The waist is defined as fwhm/sqrt(2*log(2)) and correspond to the 1/e
            field value and 1/:math:`e^2` intensity value.

            Parameters
            ----------
            fwhm : float
                Full width at half maximum (for intensity not amplitude) (µm).
            offset_light : float, optional
                Light offset from center in µm. 0 by default.

            Returns
            -------
            field : array
                Amplitude values over x in µm.

            Notes
            -----
            This methods uses the x and dist_x variables defined in :class:`Bpm`.
            """
            spot_size = fwhm / sqrt(2 * log(2))  # such as I=1/e^2 in intensity
            if spot_size != 0:
                field = np.exp(-(self.x / spot_size)**2)
                field = np.roll(field, int(round(offset_light / self.dist_x)))
            else:
                field = 0 * self.x  # Avoid division by zero error
            return field

        def squared_light(self, fwhm, offset_light=0):
            """
            Create a flat-top beam (squared).

            Parameters
            ----------
            fwhm : float
                Width in µm.
            offset_light : float, optional
                Light offset from center in µm. 0 by default.

            Returns
            -------
            field : array
                Amplitude values over x in µm.

            Notes
            -----
            This methods uses the following variables defined in :class:`Bpm`:
            nbr_x, x.
            """
            field = np.zeros(self.nbr_x)

            for j in range(self.nbr_x):
                if (self.x[j] >= -fwhm/2
                        and self.x[j] <= fwhm/2):
                    field[j] = 1
                else:
                    field[j] = 0

            field = np.roll(field, int(round(offset_light / self.dist_x)))
            return field

        def mode_determ(self, mode):
            """
            Solve the transcendental equation tan=sqrt that give the modes
            allowed in a squared guide.

            Parameters
            ----------
            mode : int
                Number of the searched mode.

            Returns
            -------
            h_m : float
                Transverse propagation constant over x (µm).
            gamma_m : float
                Extinction coefficient over x (µm).
            beta_m : float
                Longitudinal constant of propagation over z (µm).

            Raises
            ------
            ValueError
                if no mode exists.

            Notes
            -----
            This methods uses the following variables defined in :class:`Bpm`:
            lo, width, no, delta_no, ko.
            """
            lim = self.lo/(2 * self.width * (self.no + self.delta_no)) - 1e-12
            theta_c = acos(self.no / (self.no + self.delta_no))  # Critical angle
            solu = np.linspace(
                mode*lim + 0.000001,
                (mode + 1) * lim,
                round(1 + (lim - 0.000001)/0.000001))
            lhs = np.tan(
                pi * self.width * (self.no + self.delta_no) / self.lo * solu
                - mode*pi/2)
            rhs = np.sqrt(
                0j  # to avoid sqrt error when complexe
                + (sin(theta_c) / solu)**2
                - 1)
            result = rhs - lhs  # 0 if left == right
            minimum = abs(result).min()  # return min value : where two equations~=
            i_min = int(np.where(abs(result) == minimum)[0])  # min value index

            if i_min == 0:
                raise ValueError("no mode " + str(mode) + " existing")

            sin_theta_m = solu[i_min]
            theta_m = asin(sin_theta_m)  # angle at which the mode propagate

            beta_m = self.ko * (self.no + self.delta_no) * cos(theta_m)
            h_m = sqrt((self.ko * (self.no + self.delta_no))**2 - beta_m**2)
            gamma_m = (self.no * self.ko
                       * np.sqrt((cos(theta_m) / cos(theta_c))**2 - 1))

            return [h_m, gamma_m, beta_m]

        def mode_light(self, mode, lo, offset_light=0):
            """
            Create light based on propagated mode inside a squared guide.

            Parameters
            ----------
            mode : int
                Number of the searched mode.
            lo : float
                Wavelength of the beam in vaccum (µm).
            offset_light : float, optional
                Light offset from center (µm). 0 by default.

            Returns
            -------
            field : array
                Amplitude values over x (µm).
            h_m : float
                Transverse propagation constant over x (µm).
            gamma_m : float
                Extinction coefficient over x (µm).
            beta_m : float
                Longitudinal constant of propagation over z (µm).

            Notes
            -----
            This methods uses the following variables defined in :class:`Bpm`:
            nbr_x, width, x and the :meth`mode_determ` method.

            This method create the following variables in :class:`Bpm`:
            lo, ko.
            """
            self.lo = lo
            self.ko = 2 * pi / self.lo  # linear wave vector in free space (1/µm)
            field = np.zeros(self.nbr_x)

            [h_m, gamma_m, beta_m] = self.mode_determ(mode)

            if mode % 2 == 0:  # if even mode

                b_b = cos(h_m * self.width / 2)  # Continuity value where x=width/2

                for j in range(self.nbr_x):  # Compute light based on h,gamma,beta

                    if abs(self.x[j]) <= self.width/2:  # in core
                        field[j] = cos(h_m * self.x[j])

                    else:  # in cladding
                        field[j] = b_b * exp(-gamma_m * (
                            abs(self.x[j])
                            - self.width/2))
            else:  # if odd mode

                c_c = sin(h_m * self.width / 2)  # Continuity value where x=width/2

                for j in range(self.nbr_x):  # Compute light based on h,gamma,beta

                    if abs(self.x[j]) <= self.width/2:  # in core
                        field[j] = sin(h_m * self.x[j])

                    elif self.x[j] >= self.width/2:  # Right cladding
                        field[j] = c_c * exp(-gamma_m * (
                            self.x[j]
                            - self.width/2))

                    else:  # Left cladding
                        field[j] = -c_c * exp(gamma_m * (
                            self.x[j]
                            + self.width/2))

            field = np.roll(field, int(round(offset_light / self.dist_x)))

            return [field, h_m, gamma_m, beta_m]

        def all_modes(self, lo, offset_light=0):
            """
            Compute all modes allowed by the guide and sum them into one field.

            Parameters
            ----------
            lo : float
                Wavelength of the beam in vaccum in µm.
            offset_light : float, optional
                Light offset from center in µm. 0 by default.

            Returns
            -------
            field : array
                Sum of all possibles fields in the guide.
            h : array, float
                Transverse propagation constant over x in µm of all modes.
            gamma : array, float
                Extinction coefficient over z in µm of all modes.
            beta : array, float
                Longitudinal constant of propagation over z in µm of all modes.

            Notes
            -----
            This methods uses the following variables defined in :class:`Bpm`:
            nbr_x and the :meth`mode_light` method.
            """
            i = 0
            field = np.zeros(self.nbr_x)
            h = np.array([])
            gamma = np.array([])
            beta = np.array([])

            while True:
                try:
                    [field_i, h_m, gamma_m, beta_m] = self.mode_light(
                        i, lo, offset_light)
                    field = field + field_i
                    h = np.append(h, h_m)
                    gamma = np.append(gamma, gamma_m)
                    beta = np.append(beta, beta_m)
                    i += 1
                except ValueError:
                    break

            return [field, h, gamma, beta]

        def check_modes(self, lo):
            """
            Return the last possible mode number.
            Could be merged with :meth:`all_modes` but would increase the needed
            time to compute just to display a number.

            Parameters
            ----------
            lo : float
                Wavelength of the beam in vaccum (µm).

            Returns
            -------
            m : int
                Number of the last possible mode for a squared guide.

            Notes
            -----
            This methods uses the :meth`mode_light` method defined in :class:`Bpm`.
            """
            i = 1

            while True:
                try:
                    self.mode_light(i, lo)
                    i += 1
                except ValueError:
                    print("This guide can propagate up to the modes", i-1)
                    return i-1

        def airy_light(self, lobe_size, airy_zero, offset_light=0):
            """
            Create an Airy beam using scipy.special.airy(x).

            Parameters
            ----------
            lobe_size : float
                Size of the first lobe (µm).
            airy_zero : int
                Cut the beam at the asked zero of the Airy function. n lobes will
                be displayed.
            offset_light : float, optional
                Light offset from center in µm. 0 by default.

            Returns
            -------
            field : array
                Amplitude values over x (µm).
            airy_zero : int
                Number of lobes. Corrected if higher than the window size.

            Notes
            -----
            This methods uses the following variables defined in :class:`Bpm`:
            nbr_x, length_x, dist_x, x.
            """
            if lobe_size == 0 or airy_zero == 0:
                return [np.zeros(self.nbr_x), 0]

            lobe_size = -abs(lobe_size)

            # Position of the first zero and the asked one
            zero_pos = special.ai_zeros(airy_zero)[0]
            first_zero = zero_pos[0]
            last_zero = zero_pos[-1]

            # Positions/size of the wanted beam
            left = last_zero * lobe_size / first_zero
            right = 10 * lobe_size / first_zero  # Airy=1e-10 at x=10

            # Reduce the last zero number to stay in the window
            if -left > self.length_x:
                left = zero_pos * lobe_size / first_zero  # All possibles left posi
                airy_zero = np.where(-left <= self.length_x)[0]  # Higher index

                if airy_zero.size == 0:  # interface don't allow this situation
                    print("The first lobe is bigger than the windows size")
                    return [np.zeros(self.nbr_x), 0]

                else:  # take the higher lobe possible
                    airy_zero = int(airy_zero[-1])

                last_zero = zero_pos[airy_zero]  # Value of the last lobe
                airy_zero += 1  # +1 to return the zero number

                left = last_zero * lobe_size / first_zero  # Corrected left positio

            # Number of points in the Airy window to match the full window
            nbr_point = int(round(abs((left - right) / self.dist_x)))

            # Airy window size
            x_airy = np.linspace(last_zero, 10, nbr_point)

            # Positions of the Airy and full window center
            center_airy = int(np.where(x_airy >= 0)[0][0])
            center = int(np.where(self.x >= 0)[0][0])

            # Airy field
            field = np.array(special.airy(x_airy)[0])

            # add last empty field to reach the windows size
            if self.x.size > field.size:
                field = np.append(field, np.zeros((self.x.size-field.size)))

            else:
                field.resize(self.x.size)  # Cut if exceed windows size

            # Recenter on 0
            field = np.roll(field, int(round(center - center_airy)))

            field = np.roll(field, int(round(offset_light / self.dist_x)))
            field /= max(field)  # Normalized

            return [field, airy_zero]

        def init_field(self, field, theta_ext, irrad, lo):
            """
            Initialize phase, field and power variables.

            Parameters
            ----------
            field : array, array-like
                Amplitude values for each beams over x (µm) [beam,E] or E
            theta_ext : float
                Exterior inclinaison angle (°).
            irrad : array, array-like
                Irradiance or power for each beam (:math:`W/m^2`).
            lo : float
                Wavelenght (µm).

            Returns
            -------
            progress_pow : array
                Intensity values over x (µm).

            Notes
            -----
            This method creates the following variables within the class
            :class:`Bpm`:

            - epnc: Convertion factor used to set unit of the field and irradiance.
            - nl_mat: Refractive index modulation.
            - phase_mat: Free propagation in Fourier space over dz/2.
            - current_power: Intensity for z=0.
            - field: Field value with the unit.
            - ko: the free space vector (1/µm).
            - lo: Wavelenght (µm).

            This methods uses the following variables defined in :class:`Bpm`:
            no, x, dist_x, nbr_x, nbr_z_disp.
            """
            self.lo = lo
            self.field = field.astype(complex)
            # see en.wiki: Gaussian_beam#Mathematical_form for intensity definition
            Zo = 376.730313668  # Impedance of free space mu_0*c
            self.epnc = self.no / Zo / 2  # = 1 / (2 eta) used to converte E into I
            #  unit(epnc)= W/V^2

            try:  # if multiple beams or one beam as [beam]
                _ = self.field.shape[1]  # Raise a IndexError if not
                nbr_light = self.field.shape[0]  # [beam1,beam2,beam3] -> 3
    #            Eo = sqrt(irrad[i] / self.epnc)  # Peak value of the field (V/m).

                for i in range(nbr_light):
                    self.field[i] *= sqrt(irrad[i] / self.epnc)

                self.field = np.sum(self.field, axis=0)  # merge all beam into one

            except IndexError:  # if only one beam and not in form [beam]
                self.field *= sqrt(irrad / self.epnc)

    #        https://support.lumerical.com/hc/en-us/articles/
    #        360034382894-Understanding-injection-angles-in-broadband-simulations
            self.ko = 2 * pi / self.lo  # linear wave vector in free space (1/µm)
            theta = asin(sin(radians(theta_ext)) / self.no)  # angle in the guide
            ph = self.no * self.ko * sin(theta) * self.x  # k projection over x
            self.field *= np.exp(1j * ph)  # Initial phase due to angle

            nu_max = 1 / (2*self.dist_x)  # max frequency due to sampling
            # Spacial frequencies over x (1/µm)
            nu = np.linspace(-nu_max,
                             nu_max * (1 - 2/self.nbr_x),
                             self.nbr_x)
            intermed = self.no * cos(theta) / self.lo
            # Linear propagation phase
            fr = 2 * pi * nu**2 / (intermed + np.sqrt(
                intermed**2
                - nu**2
                + 0j))

            # Free space matrix
            self.phase_mat = fftshift(np.exp(-1j * self.dist_z / 2 * fr))

            # Refractive index modulation
            self.nl_mat = self.ko * self.dist_z * self.dn

            # Initial irradiance
            self.current_power = self.epnc * (
                self.field * self.field.conjugate()).real

            self.progress_pow = np.zeros([self.nbr_z_disp, self.nbr_x])
            self.progress_pow[0, :] = np.array([self.current_power])

            return [self.progress_pow]

        def guide_position(self, guide, size):
            """
            Return the left and right position index over x of a given guide
            for each z.

            Parameters
            ----------
            guide : int
                Number of the guide.
            size : float
                Width (µm).

            Returns
            -------
            x_beg : array
                Left indices position of the selected guide over z.
            x_end : array
                Right indices position of the selected guide over z.

            Notes
            -----
            This methods uses the following variables defined in :class:`Bpm`:
            nbr_z, peaks, x, length_x.
            """
            x_beg = np.zeros(self.nbr_z, dtype=int)  # Note: don't use x_end=x_beg
            x_end = np.zeros(self.nbr_z, dtype=int)  # Because id would be ==

            if self.peaks.shape[0] != 0:

                for j in range(self.nbr_z):

                    pos_beg = (self.peaks[guide, j] - size/2)  # Left position

                    # If the position is out of boundery, change interval to
                    # (-length_x/2, length_x)
                    if pos_beg < self.x[0] or pos_beg > self.x[-1]:
                        pos_beg = pos_beg % self.length_x

                    # If the pos_beg is between length_x/2 and length_x then change
                    # interval to (-length_x/2, length_x/2)
                    if pos_beg >= self.x[-1]:
                        pos_beg -= self.length_x

                    # Search the closest index value for this position
                    x_beg[j] = np.where(self.x >= pos_beg)[0][0]

                    pos_end = (self.peaks[guide, j] + size/2)

                    if pos_end < self.x[0] or pos_end > self.x[-1]:
                        pos_end = pos_end % self.length_x

                    if pos_end >= self.x[-1]:
                        pos_end -= self.length_x

                    x_end[j] = np.where(self.x >= pos_end)[0][0]

            return [x_beg, x_end]

        def power_guide(self, x_beg, x_end):
            """
            return the approximative power over z in a given guide.
            A better method would be to deconvolve the beams.

            Parameters
            ----------
            x_beg : array
                Left indices position over z for a selected guide.
            x_end : array
                Right indices position over z for a selected guide.

            Returns
            -------
            P : array
                Power in the guide over z.

            Notes
            -----
            This methods uses the following variables defined in :class:`Bpm`:
            nbr_z_disp, progress_pow.
            """
            P = np.zeros(self.nbr_z_disp)

            for i in range(self.nbr_z_disp):

                if x_beg[i] <= x_end[i]:
                    P[i] = np.trapz(self.progress_pow[i, x_beg[i]:x_end[i]])

                else:  # Take into account guides that crosses the window edges
                    P[i] = np.trapz(self.progress_pow[i, x_beg[i]:])
                    P[i] += np.trapz(self.progress_pow[i, :x_end[i]])

            P /= np.trapz(self.progress_pow[0, ], axis=0)
            return P

        def losses_position(self, guide_lost, width_lost):
            """
            Return the left and right position (x) index of a given area
            over z [x,z].

            Parameters
            ----------
            guide_lost : array
                Number of each guide where looses occurs.
            width_lost : array
                Half width in µm for each guide.

            Returns
            -------
            lost_beg : array-like
                Left indices position of the selected guides over z.
            lost_end : array-like
                Right indices position of the selected guides over z.

            Notes
            -----
            This methods uses the nbr_z variables defined in :class:`Bpm` and
            the :meth:`guide_position` method.
            It also creates the nbr_lost variable shared with :class:`Bpm`.
            """
            self.nbr_lost = guide_lost.size
            lost_beg = np.zeros((self.nbr_z, self.nbr_lost), dtype=int)
            lost_end = np.zeros((self.nbr_z, self.nbr_lost), dtype=int)
            for j, n in enumerate(guide_lost):
                [lost_beg[:, j],
                 lost_end[:, j]] = self.guide_position(n, width_lost[j])

            return [lost_beg, lost_end]

        def kerr_effect(self, chi3=1e-19, kerr_loop=1, variance_check=False,
                        field_start=None, dn_start=None, phase_mat=None):
            """
            Kerr effect: refractive index modulation by the light intensity.
            See: https://optiwave.com/optibpm-manuals/bpm-non-linear-bpm-algorithm/

            Parameters
            ----------
            chi3 : float, optional
                Value of the third term of the electric susceptibility tensor.
                Equals to :math:`10^{-19} m^2/V^2` by default.
            kerr_loop : int, optional
                Number of corrective loops for the Kerr effect. 1 by default.
            variance_check : bool, optional
                Check if the kerr effect converge fast enought. False by default.
            field_start : array, optional
                Field without kerr effect.
                If None were given, take the :meth:`main_compute` field.
            dn_start : array, optional
                Refractive index without kerr effect.
                If None were given, take the :meth:`main_compute` dn.
            phase_mat: array, optional
                Free propagation in Fourier space over dz/2.
                If None were given, take the :meth:`main_compute` phase_mat.

            Returns
            -------
            dn : array
                Refractive index with kerr effect.
            nl_mat : array
                refractive index modulation with kerr effect.
            field_x : array
                Field with the kerr effect at the self.i step.
            cur_pow : array
                Beam power with the kerr effect after the dz propagation.

            Notes
            -----
            This methods uses the following variables defined in :class:`Bpm`:
            i, epnc, no, ko, dist_z and the :meth:`variance` method.
            """
            # Set the default value if none were given
            dn_start = self.dn[self.i, :] if dn_start is None else dn_start
            nl_mat = self.ko * self.dist_z * dn_start
            field_start = self.field if field_start is None else field_start
            phase_mat = self.phase_mat if phase_mat is None else phase_mat

            # Influence of the index modulation on the field
            field_x = field_start * np.exp(1j * nl_mat)

            # Linear propagation over dz/2
            field_x = ifft(phase_mat * fft(field_x))

            cur_pow = self.epnc * (field_x * field_x.conjugate()).real

            for _ in range(kerr_loop):
                prev_pow = cur_pow

                # influence of the beam intensity on the index modulation
                # dn = dn1+dn2*I with dn2 unit: m^2/W
                dn = dn_start + (3 * chi3 / 8 / self.no * prev_pow)
                nl_mat = self.ko * self.dist_z * dn

                # influence of the index modulation on the field
                field_x = field_start * np.exp(1j * nl_mat)

                # Linear propagation over dz/2
                field_x = ifft(phase_mat * fft(field_x))

                # power at z
                cur_pow = self.epnc * (field_x * field_x.conjugate()).real

            if variance_check:

                try:
                    self.variance(prev_pow, cur_pow)  # Check if converge

                except ValueError as ex:
                    print(ex)
                    print("for the step i=", self.i)

                if max(dn) > self.no/10:
                    print("Warning: Index variation too high:")
                    print(round(max(dn), 2), ">", self.no, "/10")

            return [dn, nl_mat, field_x, cur_pow]

        def variance(self, initial, final):
            """
            This method alerts the user when the kerr effect don't converge fast
            enought.
            Raise a ValueError when the power standard deviation exceed
            :math:`10^{-7}`.

            Parameters
            ----------
            initial : array
                Power of the kerr effect looped n-1 time.
            final : array
                Power of the kerr effect looped n time.

            Raises
            ------
            ValueError
                when the power standard deviation exceed :math:`10^{-7}`.
            """
            finish_sum = sum(final)
            self.nl_control_amp = 1 / finish_sum * sqrt(abs(
                sum((final - initial)**2) - (sum(final - initial))**2))

            if self.nl_control_amp > 1e-7:
                message = "Warning: don't converge fast enough " + \
                    "for a deviation of " + str(self.nl_control_amp)
                raise ValueError(message)

        def absorption(self, alpha, lost_beg, lost_end):
            """
            Absorption into a guide or several guides.

            :math:`e^{-\\alpha * dz}`

            Parameters
            ----------
            alpha : float
                Absorption per µm.
            lost_beg : array-like
                Left indices position of the selected guides over z.
            lost_end : array-like
                Right indices position of the selected guides over z.

            Returns
            -------
            field : array
                Amplitude values over x in µm after looses.

            Notes
            -----
            This methods uses the following variables defined in :class:`Bpm`:
            nbr_lost, i, field, dist_z, nbr_x.
            """
            for n in range(self.nbr_lost):

                if lost_beg[self.i, n] <= lost_end[self.i, n]:  # Normal case

                    for j in range(lost_beg[self.i, n], lost_end[self.i, n]+1):
                        self.field[j] *= exp(-alpha * self.dist_z)

                else:  # Take into account guide crossing the window edges

                    for j in range(lost_beg[self.i, n], self.nbr_x):
                        self.field[j] *= exp(-alpha * self.dist_z)

                    for j in range(0, lost_end[self.i, n]+1):
                        self.field[j] *= exp(-alpha * self.dist_z)

            return self.field

        def bpm_compute(self, chi3=1e-19, kerr=False, kerr_loop=1,
                        variance_check=False,
                        alpha=0, lost_beg=None, lost_end=None):

            """
            Compute BPM principle : free_propag over dz/2, index modulation,
            free_propag over dz/2.

            Parameters
            ----------
            chi3 : float, optional
                Value of the effective third term of the electric susceptibility
                tensor. Equals to :math:`10^{-19} m^2/V^2` by default.
            kerr : bool, optional
                Activate the kerr effect. False by default.
            kerr_loop : int, optional
                Number of corrective loops for the Kerr effect. 1 by default.
            variance_check : bool
                Check if the kerr effect converge fast enought. False by default.
            alpha : float, optional
                Absorption per µm. 0 by default.
            lost_beg : array-like, optional
                Left indices position of the selected guides over z.
                None by default.
            lost_end : array-like, optional
                Right indices position of the selected guides over z.
                None by default.

            Returns
            -------
            current_power : array
                Power after the propagation over dz.

            Notes
            -----
            This method uses the :class:`Bpm` class variables:
            nbr_lost, i, field, dist_z, dn, nl_mat, phase_mat, epnc.

            This method change the values of:
            field, dn, nl_mat, current_power.
            """
            # Linear propagation over dz/2
            self.field = ifft(self.phase_mat * fft(self.field))

            # Absorption into a guide
            if alpha != 0:
                self.field = self.absorption(alpha, lost_beg, lost_end)

            if kerr:
                [self.dn[self.i, :], self.nl_mat[self.i, :],
                 self.field, self.current_power] = self.kerr_effect(
                     chi3=chi3, kerr_loop=kerr_loop, variance_check=variance_check)
            else:
                # Influence of the index modulation on the field
                self.field *= np.exp(1j * self.nl_mat[self.i, :])

                # Linear propagation over dz/2
                self.field = ifft(self.phase_mat * fft(self.field))

                # power at z
                self.current_power = self.epnc * (
                    self.field * self.field.conjugate()).real

            # useless but act as a reminder for what the the method does
            return self.current_power

        def main_compute(self, chi3=1e-19, kerr=False, kerr_loop=1,
                         variance_check=False,
                         alpha=0, lost_beg=None, lost_end=None):
            """
            main method used to compute propagation.

            Parameters
            ----------
            chi3 : float, optional
                Value of the third term of the electric susceptibility tensor.
                Equals to :math:`10^{-19} m^2/V^2` by default.
            kerr : bool, optional
                Activate the kerr effect. False by default.
            kerr_loop : int, optional
                Number of corrective loop for the Kerr effect. 1 by default.
            variance_check : bool, optional
                Check if the kerr effect converge fast enought. False by default.
            alpha : float, optional
                Absorption per µm. 0 by default
            lost_beg : array-like, optional
                Left indices position of the selecteds guide over z.
                None by default.
            lost_end : array-like, optional
                Right indices position of the selecteds guide over z.
                None by default.

            Returns
            -------
            progress_pow : array
                Intensity values (:math:`W/m^2`) over x (µm) and z (µm).

            Notes
            -----
            This methood uses the :class:`Bpm` class variables:
            phase_mat, field, i, nbr_z, pas, current_power, dist_z, length_z,
            nbr_lost, dn, nl_mat, epnc and uses the :meth:`bpm_compute`,
            :meth:`kerr_effect`.

            This method change the values of the :class:`Bpm` class variables:
            field and if kerr, dn and nl_mat.
            """
            index = 0
            self.i = 0
            #  from i=0 to i=final-1 because don't use last dn
            for i in range(0, self.nbr_z-1):
                self.i = i
                # Compute non-linear and linear propagation for every z
                self.bpm_compute(
                    chi3=chi3, kerr=kerr, kerr_loop=kerr_loop,
                    variance_check=variance_check, alpha=alpha,
                    lost_beg=lost_beg, lost_end=lost_end)

                # Display condition: if i+1 is a multiple of pas: i+1 % pas = 0
                # = False, so must use if not to have True
                # last condition to have last point if not a multiple of pas
                if not (self.i + 1) % self.pas or self.i+1 == self.nbr_z-1:
                    index += 1
                    self.progress_pow[index, :] = np.array([self.current_power])

                    print((self.i+1)*self.dist_z/1e3, "/", self.length_z/1e3, 'mm')

            return [self.progress_pow]

    def example_bpm():
        """
        Version allowing to compute BPM without the user interface.
        Used for quick test.
        """
        width = 6
        no = 2.14
        delta_no = 0.001
        length_z = 10000
        dist_z = 1
        nbr_z_disp = 200
        dist_x = 0.1
        length_x = 500

        bpm = Bpm(width, no, delta_no,
                  length_z, dist_z, nbr_z_disp,
                  length_x, dist_x)

        [length_z, nbr_z, nbr_z_disp, length_x, nbr_x, x] = bpm.create_x_z()

    #    shape = bpm.squared_guide()
        shape = bpm.gauss_guide(4)

        nbr_p = 3
        p = 13
        offset_guide = 0

        [peaks, dn] = bpm.create_guides(
            shape, nbr_p, p, offset_guide=offset_guide)
    #    curve = 40 * 1E-8
    #    half_delay = 1000
    #    distance_factor = 1.2
    #    [peaks, dn] = bpm.create_curved_guides(shape, curve, half_delay,
    #                                           distance_factor,
    #                                           offset_guide=offset_guide)

        z_disp = np.linspace(0, length_z/1000, nbr_z_disp+1)
        xv, zv = np.meshgrid(x, z_disp)
        dn_disp = np.linspace(0, nbr_z-1, nbr_z_disp+1, dtype=int)

    #    plt.figure()
    #    for i in range(nbr_z_disp+1):
    #        plt.plot(x,dn[i,:])

        plt.figure()
        plt.pcolormesh(xv,
                       zv,
                       dn[dn_disp],
                       cmap='gray')
        fwhm = 6
        offset_light = peaks[1, 0]  # If guide exists
    #        offset_light = 0  # Else
        lo = 1.5
        nbr_light = 1
        field = np.array([np.zeros(nbr_x)] * nbr_light)
        for i in range(nbr_light):
            field_i = bpm.gauss_light(fwhm, offset_light=offset_light)

        #    field_i = bpm.squared_light(fwhm, offset_light=offset_light)

    #            [field_i, h, gamma, beta] = bpm.all_modes(
    #                lo, offset_light=offset_light)

    #        mode = 0
    #            [field_i, h, gamma, beta] = bpm.mode_light(
    #                mode, lo, offset_light=offset_light)

            field[i] = field_i

        irrad = [1 * 1E13]*nbr_light
        theta_ext = 0
        [progress_pow] = bpm.init_field(field, theta_ext, irrad, lo)

        def _show_plot(pow_index):
            plt.figure()
            ax1 = plt.subplot(111)
            if pow_index == 0:
                ax1.set_title("Light injection into a guide")
            else:
                ax1.set_title("Light at the end of guides")
            ax1.set_xlabel('x (µm)')
            ax2 = ax1.twinx()
            for tl in ax1.get_yticklabels():
                tl.set_color('k')
            for tl in ax2.get_yticklabels():
                tl.set_color('#1f77b4')
            ax1.set_ylabel(r'$\Delta_n$')
            ax2.set_ylabel('Irradiance ($GW.cm^{-2}$)')

            if nbr_p != 0 and p != 0:
                ax1.set_xlim(-nbr_p*p, nbr_p*p)
                verts = [(x[0], 0),
                         *zip(x, dn[pow_index, :]),
                         (x[-1], 0)
                         ]
                poly = Polygon(verts, facecolor='0.9', edgecolor='0.5')
                ax1.add_patch(poly)
            ax1.set_ylim(0,
                         max(dn[0, :])*1.1 + 1E-20
                         )
            if max(progress_pow[0]) != 0:
                ax2.set_ylim(0,
                             1e-13 * max(progress_pow[0]) * 1.1)

            ax1.plot(x, dn[pow_index], 'k')
            ax2.plot(x, 1e-13*progress_pow[pow_index], '#1f77b4')
            plt.show()

        pow_index = 0
        print("close the graph to continue")
        _show_plot(pow_index)

        kerr = False
        kerr_loop = 10
        variance_check = False
        chi3 = 10 * 1E-20

        lost_check = 0
        guide_lost = 1
        width_lost = width
        alpha = 0.8

        if lost_check:
            guide_lost = np.array([guide_lost], dtype=int)
            width_lost = np.array([width_lost])
            alpha = alpha/1000
            [lost_beg, lost_end] = bpm.losses_position(
                guide_lost, width_lost)
        else:
            alpha = 0
            lost_beg = 0
            lost_end = 0

        estimation = round(
            8.8 / 5e7 * nbr_z * nbr_x  # without kerr
            * (1 + 0.72*float(kerr)*(kerr_loop))  # with kerr
            + 3.8/5e6*nbr_z*nbr_x*float(variance_check)  # control
            + 9/1e7*nbr_z*width_lost/dist_x*lost_check,
            1)  # looses

        print("Time estimate:", str(estimation))

        debut = time.process_time()
        [progress_pow] = bpm.main_compute(
            chi3=chi3, kerr=kerr, kerr_loop=kerr_loop,
            variance_check=variance_check, alpha=alpha,
            lost_beg=lost_beg, lost_end=lost_end)
        fin = time.process_time()
        print('temps : ', fin-debut)

        plt.figure()
        ax1 = plt.subplot(111)
        ax1.set_title("Light propagation into guides")
        ax1.set_xlabel('x (µm)')
        ax1.set_ylabel('z (mm)')
        if nbr_p != 0 and p != 0:
            ax1.set_xlim(-nbr_p*p, nbr_p*p)
        ax1.pcolormesh(xv, zv, 1e-13*progress_pow)

        pow_index = -2
        print("close the graphs to continue")
        _show_plot(pow_index)
        print("Finished")

    if __name__ == "__main__":
        print("version without the user interface, note that user_interface.py")
        print("calls the Bpm class and performs the same calculations")

        choice = input("Start ?: ")

        if not choice != "yes":
            example_bpm()

## beampy.interface

    # -*- coding: utf-8 -*-

    # Form implementation generated from reading ui file 'interface.ui'
    #
    # Created by: PyQt5 UI code generator 5.13.1
    #
    # WARNING! All changes made in this file will be lost!

    from PyQt5 import QtCore, QtGui, QtWidgets

    class Ui_MainWindow(object):
        def setupUi(self, MainWindow):
            MainWindow.setObjectName("MainWindow")
            MainWindow.resize(1144, 1019)
            MainWindow.setMinimumSize(QtCore.QSize(800, 935))
            self.centralwidget = QtWidgets.QWidget(MainWindow)
            self.centralwidget.setObjectName("centralwidget")
            self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
            self.gridLayout.setObjectName("gridLayout")
            self.frame_file_data = QtWidgets.QFrame(self.centralwidget)
            self.frame_file_data.setFrameShape(QtWidgets.QFrame.NoFrame)
            self.frame_file_data.setFrameShadow(QtWidgets.QFrame.Raised)
            self.frame_file_data.setObjectName("frame_file_data")
            self.verticalLayout = QtWidgets.QVBoxLayout(self.frame_file_data)
            self.verticalLayout.setObjectName("verticalLayout")
            self.tabWidget_main = QtWidgets.QTabWidget(self.frame_file_data)
            self.tabWidget_main.setObjectName("tabWidget_main")
            self.tabWidget_guide = QtWidgets.QWidget()
            self.tabWidget_guide.setObjectName("tabWidget_guide")
            self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.tabWidget_guide)
            self.horizontalLayout_2.setObjectName("horizontalLayout_2")
            self.verticalLayout_guide = QtWidgets.QVBoxLayout()
            self.verticalLayout_guide.setObjectName("verticalLayout_guide")
            self.label_window_parameters = QtWidgets.QLabel(self.tabWidget_guide)
            self.label_window_parameters.setMinimumSize(QtCore.QSize(0, 62))
            self.label_window_parameters.setMaximumSize(QtCore.QSize(16777215, 62))
            self.label_window_parameters.setObjectName("label_window_parameters")
            self.verticalLayout_guide.addWidget(self.label_window_parameters)
            self.frame_window = QtWidgets.QFrame(self.tabWidget_guide)
            self.frame_window.setMinimumSize(QtCore.QSize(370, 0))
            self.frame_window.setMaximumSize(QtCore.QSize(370, 16777215))
            self.frame_window.setFrameShape(QtWidgets.QFrame.Box)
            self.frame_window.setFrameShadow(QtWidgets.QFrame.Raised)
            self.frame_window.setObjectName("frame_window")
            self.formLayout_10 = QtWidgets.QFormLayout(self.frame_window)
            self.formLayout_10.setObjectName("formLayout_10")
            self.label_length = QtWidgets.QLabel(self.frame_window)
            self.label_length.setAccessibleDescription("")
            self.label_length.setOpenExternalLinks(False)
            self.label_length.setObjectName("label_length")
            self.formLayout_10.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_length)
            self.doubleSpinBox_length_z = QtWidgets.QDoubleSpinBox(self.frame_window)
            self.doubleSpinBox_length_z.setMinimumSize(QtCore.QSize(0, 0))
            self.doubleSpinBox_length_z.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_length_z.setDecimals(3)
            self.doubleSpinBox_length_z.setMinimum(0.001)
            self.doubleSpinBox_length_z.setMaximum(100000.0)
            self.doubleSpinBox_length_z.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType)
            self.doubleSpinBox_length_z.setProperty("value", 10000.0)
            self.doubleSpinBox_length_z.setObjectName("doubleSpinBox_length_z")
            self.formLayout_10.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_length_z)
            self.label_dist_z = QtWidgets.QLabel(self.frame_window)
            self.label_dist_z.setObjectName("label_dist_z")
            self.formLayout_10.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_dist_z)
            self.doubleSpinBox_dist_z = QtWidgets.QDoubleSpinBox(self.frame_window)
            self.doubleSpinBox_dist_z.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_dist_z.setDecimals(3)
            self.doubleSpinBox_dist_z.setMinimum(0.001)
            self.doubleSpinBox_dist_z.setMaximum(100000.0)
            self.doubleSpinBox_dist_z.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType)
            self.doubleSpinBox_dist_z.setProperty("value", 1.0)
            self.doubleSpinBox_dist_z.setObjectName("doubleSpinBox_dist_z")
            self.formLayout_10.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_dist_z)
            self.label_nbr_z_disp = QtWidgets.QLabel(self.frame_window)
            self.label_nbr_z_disp.setObjectName("label_nbr_z_disp")
            self.formLayout_10.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_nbr_z_disp)
            self.spinBox_nbr_z_disp = QtWidgets.QSpinBox(self.frame_window)
            self.spinBox_nbr_z_disp.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.spinBox_nbr_z_disp.setMinimum(1)
            self.spinBox_nbr_z_disp.setMaximum(10000)
            self.spinBox_nbr_z_disp.setProperty("value", 200)
            self.spinBox_nbr_z_disp.setDisplayIntegerBase(10)
            self.spinBox_nbr_z_disp.setObjectName("spinBox_nbr_z_disp")
            self.formLayout_10.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.spinBox_nbr_z_disp)
            self.label_length_x = QtWidgets.QLabel(self.frame_window)
            self.label_length_x.setObjectName("label_length_x")
            self.formLayout_10.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_length_x)
            self.doubleSpinBox_length_x = QtWidgets.QDoubleSpinBox(self.frame_window)
            self.doubleSpinBox_length_x.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_length_x.setDecimals(3)
            self.doubleSpinBox_length_x.setMinimum(0.001)
            self.doubleSpinBox_length_x.setMaximum(10000.0)
            self.doubleSpinBox_length_x.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType)
            self.doubleSpinBox_length_x.setProperty("value", 1000.0)
            self.doubleSpinBox_length_x.setObjectName("doubleSpinBox_length_x")
            self.formLayout_10.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_length_x)
            self.label_dist_x = QtWidgets.QLabel(self.frame_window)
            self.label_dist_x.setObjectName("label_dist_x")
            self.formLayout_10.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_dist_x)
            self.doubleSpinBox_dist_x = QtWidgets.QDoubleSpinBox(self.frame_window)
            self.doubleSpinBox_dist_x.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_dist_x.setDecimals(3)
            self.doubleSpinBox_dist_x.setMinimum(0.001)
            self.doubleSpinBox_dist_x.setMaximum(100.0)
            self.doubleSpinBox_dist_x.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType)
            self.doubleSpinBox_dist_x.setProperty("value", 0.2)
            self.doubleSpinBox_dist_x.setObjectName("doubleSpinBox_dist_x")
            self.formLayout_10.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_dist_x)
            self.verticalLayout_guide.addWidget(self.frame_window)
            spacerItem = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum)
            self.verticalLayout_guide.addItem(spacerItem)
            self.label_guides_information = QtWidgets.QLabel(self.tabWidget_guide)
            self.label_guides_information.setMinimumSize(QtCore.QSize(0, 62))
            self.label_guides_information.setMaximumSize(QtCore.QSize(16777215, 62))
            self.label_guides_information.setObjectName("label_guides_information")
            self.verticalLayout_guide.addWidget(self.label_guides_information)
            self.frame_guides = QtWidgets.QFrame(self.tabWidget_guide)
            self.frame_guides.setMinimumSize(QtCore.QSize(370, 0))
            self.frame_guides.setMaximumSize(QtCore.QSize(370, 16777215))
            self.frame_guides.setFrameShape(QtWidgets.QFrame.Box)
            self.frame_guides.setFrameShadow(QtWidgets.QFrame.Raised)
            self.frame_guides.setObjectName("frame_guides")
            self.formLayout_6 = QtWidgets.QFormLayout(self.frame_guides)
            self.formLayout_6.setObjectName("formLayout_6")
            self.label_width = QtWidgets.QLabel(self.frame_guides)
            self.label_width.setObjectName("label_width")
            self.formLayout_6.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_width)
            self.doubleSpinBox_width = QtWidgets.QDoubleSpinBox(self.frame_guides)
            self.doubleSpinBox_width.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_width.setDecimals(3)
            self.doubleSpinBox_width.setMinimum(0.0)
            self.doubleSpinBox_width.setMaximum(10000.0)
            self.doubleSpinBox_width.setSingleStep(1.0)
            self.doubleSpinBox_width.setStepType(QtWidgets.QAbstractSpinBox.DefaultStepType)
            self.doubleSpinBox_width.setProperty("value", 8.0)
            self.doubleSpinBox_width.setObjectName("doubleSpinBox_width")
            self.formLayout_6.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_width)
            self.label_offset_guide = QtWidgets.QLabel(self.frame_guides)
            self.label_offset_guide.setObjectName("label_offset_guide")
            self.formLayout_6.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_offset_guide)
            self.doubleSpinBox_offset_guide = QtWidgets.QDoubleSpinBox(self.frame_guides)
            self.doubleSpinBox_offset_guide.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_offset_guide.setDecimals(3)
            self.doubleSpinBox_offset_guide.setMinimum(-5000.0)
            self.doubleSpinBox_offset_guide.setMaximum(5000.0)
            self.doubleSpinBox_offset_guide.setProperty("value", 0.0)
            self.doubleSpinBox_offset_guide.setObjectName("doubleSpinBox_offset_guide")
            self.formLayout_6.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_offset_guide)
            self.doubleSpinBox_n = QtWidgets.QDoubleSpinBox(self.frame_guides)
            self.doubleSpinBox_n.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_n.setDecimals(6)
            self.doubleSpinBox_n.setMinimum(1.0)
            self.doubleSpinBox_n.setMaximum(1000.0)
            self.doubleSpinBox_n.setSingleStep(0.1)
            self.doubleSpinBox_n.setProperty("value", 2.14)
            self.doubleSpinBox_n.setObjectName("doubleSpinBox_n")
            self.formLayout_6.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_n)
            self.label_n = QtWidgets.QLabel(self.frame_guides)
            self.label_n.setObjectName("label_n")
            self.formLayout_6.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_n)
            self.label_dn = QtWidgets.QLabel(self.frame_guides)
            self.label_dn.setObjectName("label_dn")
            self.formLayout_6.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_dn)
            self.doubleSpinBox_dn = QtWidgets.QDoubleSpinBox(self.frame_guides)
            self.doubleSpinBox_dn.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_dn.setDecimals(6)
            self.doubleSpinBox_dn.setMinimum(1e-06)
            self.doubleSpinBox_dn.setMaximum(1000.0)
            self.doubleSpinBox_dn.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType)
            self.doubleSpinBox_dn.setProperty("value", 0.001)
            self.doubleSpinBox_dn.setObjectName("doubleSpinBox_dn")
            self.formLayout_6.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_dn)
            self.radioButton_gaussian = QtWidgets.QRadioButton(self.frame_guides)
            self.radioButton_gaussian.setChecked(True)
            self.radioButton_gaussian.setObjectName("radioButton_gaussian")
            self.formLayout_6.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.radioButton_gaussian)
            self.spinBox_gauss_pow = QtWidgets.QSpinBox(self.frame_guides)
            self.spinBox_gauss_pow.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.spinBox_gauss_pow.setSuffix("")
            self.spinBox_gauss_pow.setMinimum(1)
            self.spinBox_gauss_pow.setMaximum(10)
            self.spinBox_gauss_pow.setSingleStep(1)
            self.spinBox_gauss_pow.setProperty("value", 4)
            self.spinBox_gauss_pow.setObjectName("spinBox_gauss_pow")
            self.formLayout_6.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.spinBox_gauss_pow)
            self.radioButton_squared = QtWidgets.QRadioButton(self.frame_guides)
            self.radioButton_squared.setObjectName("radioButton_squared")
            self.formLayout_6.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.radioButton_squared)
            self.verticalLayout_guide.addWidget(self.frame_guides)
            spacerItem1 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum)
            self.verticalLayout_guide.addItem(spacerItem1)
            self.tabWidget_morphology_guide = QtWidgets.QTabWidget(self.tabWidget_guide)
            self.tabWidget_morphology_guide.setMinimumSize(QtCore.QSize(370, 0))
            self.tabWidget_morphology_guide.setMaximumSize(QtCore.QSize(370, 16777215))
            self.tabWidget_morphology_guide.setToolTip("")
            self.tabWidget_morphology_guide.setObjectName("tabWidget_morphology_guide")
            self.tab_array = QtWidgets.QWidget()
            self.tab_array.setObjectName("tab_array")
            self.formLayout = QtWidgets.QFormLayout(self.tab_array)
            self.formLayout.setObjectName("formLayout")
            self.label_nb_p = QtWidgets.QLabel(self.tab_array)
            self.label_nb_p.setObjectName("label_nb_p")
            self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_nb_p)
            self.spinBox_nb_p = QtWidgets.QSpinBox(self.tab_array)
            self.spinBox_nb_p.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.spinBox_nb_p.setMaximum(1000)
            self.spinBox_nb_p.setProperty("value", 11)
            self.spinBox_nb_p.setObjectName("spinBox_nb_p")
            self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.spinBox_nb_p)
            self.label_p = QtWidgets.QLabel(self.tab_array)
            self.label_p.setObjectName("label_p")
            self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_p)
            self.doubleSpinBox_p = QtWidgets.QDoubleSpinBox(self.tab_array)
            self.doubleSpinBox_p.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_p.setDecimals(3)
            self.doubleSpinBox_p.setMaximum(10000.0)
            self.doubleSpinBox_p.setStepType(QtWidgets.QAbstractSpinBox.DefaultStepType)
            self.doubleSpinBox_p.setProperty("value", 15.0)
            self.doubleSpinBox_p.setObjectName("doubleSpinBox_p")
            self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_p)
            self.calculateButton_array = QtWidgets.QPushButton(self.tab_array)
            self.calculateButton_array.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
            self.calculateButton_array.setObjectName("calculateButton_array")
            self.formLayout.setWidget(3, QtWidgets.QFormLayout.SpanningRole, self.calculateButton_array)
            spacerItem2 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum)
            self.formLayout.setItem(2, QtWidgets.QFormLayout.LabelRole, spacerItem2)
            self.tabWidget_morphology_guide.addTab(self.tab_array, "")
            self.tab_curved = QtWidgets.QWidget()
            self.tab_curved.setObjectName("tab_curved")
            self.formLayout_2 = QtWidgets.QFormLayout(self.tab_curved)
            self.formLayout_2.setObjectName("formLayout_2")
            self.label_curve = QtWidgets.QLabel(self.tab_curved)
            self.label_curve.setObjectName("label_curve")
            self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_curve)
            self.doubleSpinBox_curve = QtWidgets.QDoubleSpinBox(self.tab_curved)
            self.doubleSpinBox_curve.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_curve.setDecimals(3)
            self.doubleSpinBox_curve.setMinimum(-100000000.0)
            self.doubleSpinBox_curve.setMaximum(100000000.0)
            self.doubleSpinBox_curve.setProperty("value", 40.0)
            self.doubleSpinBox_curve.setObjectName("doubleSpinBox_curve")
            self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_curve)
            self.label_half_delay = QtWidgets.QLabel(self.tab_curved)
            self.label_half_delay.setObjectName("label_half_delay")
            self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_half_delay)
            self.doubleSpinBox_half_delay = QtWidgets.QDoubleSpinBox(self.tab_curved)
            self.doubleSpinBox_half_delay.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_half_delay.setDecimals(3)
            self.doubleSpinBox_half_delay.setMaximum(100000.0)
            self.doubleSpinBox_half_delay.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType)
            self.doubleSpinBox_half_delay.setProperty("value", 1000.0)
            self.doubleSpinBox_half_delay.setObjectName("doubleSpinBox_half_delay")
            self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_half_delay)
            self.label_distance_factor = QtWidgets.QLabel(self.tab_curved)
            self.label_distance_factor.setObjectName("label_distance_factor")
            self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_distance_factor)
            self.doubleSpinBox_distance_factor = QtWidgets.QDoubleSpinBox(self.tab_curved)
            self.doubleSpinBox_distance_factor.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_distance_factor.setDecimals(3)
            self.doubleSpinBox_distance_factor.setMaximum(10000.0)
            self.doubleSpinBox_distance_factor.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType)
            self.doubleSpinBox_distance_factor.setProperty("value", 1.2)
            self.doubleSpinBox_distance_factor.setObjectName("doubleSpinBox_distance_factor")
            self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_distance_factor)
            self.calculateButton_curved = QtWidgets.QPushButton(self.tab_curved)
            self.calculateButton_curved.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
            self.calculateButton_curved.setObjectName("calculateButton_curved")
            self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.SpanningRole, self.calculateButton_curved)
            self.tabWidget_morphology_guide.addTab(self.tab_curved, "")
            self.verticalLayout_guide.addWidget(self.tabWidget_morphology_guide)
            spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
            self.verticalLayout_guide.addItem(spacerItem3)
            self.pushButton_cancel_guide = QtWidgets.QPushButton(self.tabWidget_guide)
            self.pushButton_cancel_guide.setMaximumSize(QtCore.QSize(100, 16777215))
            self.pushButton_cancel_guide.setStatusTip("")
            self.pushButton_cancel_guide.setObjectName("pushButton_cancel_guide")
            self.verticalLayout_guide.addWidget(self.pushButton_cancel_guide)
            self.horizontalLayout_2.addLayout(self.verticalLayout_guide)
            self.plot_guide = QtWidgets.QVBoxLayout()
            self.plot_guide.setObjectName("plot_guide")
            self.horizontalLayout_2.addLayout(self.plot_guide)
            self.tabWidget_main.addTab(self.tabWidget_guide, "")
            self.tabWidget_light = QtWidgets.QWidget()
            self.tabWidget_light.setObjectName("tabWidget_light")
            self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.tabWidget_light)
            self.horizontalLayout_4.setObjectName("horizontalLayout_4")
            self.verticalLayout_light = QtWidgets.QVBoxLayout()
            self.verticalLayout_light.setObjectName("verticalLayout_light")
            self.label_light_informations = QtWidgets.QLabel(self.tabWidget_light)
            self.label_light_informations.setMinimumSize(QtCore.QSize(0, 62))
            self.label_light_informations.setObjectName("label_light_informations")
            self.verticalLayout_light.addWidget(self.label_light_informations)
            self.frame_light = QtWidgets.QFrame(self.tabWidget_light)
            self.frame_light.setMaximumSize(QtCore.QSize(370, 16777215))
            self.frame_light.setFrameShape(QtWidgets.QFrame.Box)
            self.frame_light.setFrameShadow(QtWidgets.QFrame.Raised)
            self.frame_light.setObjectName("frame_light")
            self.formLayout_lo_theta = QtWidgets.QFormLayout(self.frame_light)
            self.formLayout_lo_theta.setObjectName("formLayout_lo_theta")
            self.label_lo = QtWidgets.QLabel(self.frame_light)
            self.label_lo.setObjectName("label_lo")
            self.formLayout_lo_theta.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_lo)
            self.doubleSpinBox_lo = QtWidgets.QDoubleSpinBox(self.frame_light)
            self.doubleSpinBox_lo.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_lo.setDecimals(4)
            self.doubleSpinBox_lo.setMinimum(0.01)
            self.doubleSpinBox_lo.setMaximum(100.0)
            self.doubleSpinBox_lo.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType)
            self.doubleSpinBox_lo.setProperty("value", 1.5)
            self.doubleSpinBox_lo.setObjectName("doubleSpinBox_lo")
            self.formLayout_lo_theta.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_lo)
            self.label_theta_ext = QtWidgets.QLabel(self.frame_light)
            self.label_theta_ext.setObjectName("label_theta_ext")
            self.formLayout_lo_theta.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_theta_ext)
            self.doubleSpinBox_theta_ext = QtWidgets.QDoubleSpinBox(self.frame_light)
            self.doubleSpinBox_theta_ext.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_theta_ext.setMinimum(-90.0)
            self.doubleSpinBox_theta_ext.setMaximum(90.0)
            self.doubleSpinBox_theta_ext.setObjectName("doubleSpinBox_theta_ext")
            self.formLayout_lo_theta.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_theta_ext)
            self.verticalLayout_light.addWidget(self.frame_light)
            spacerItem4 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum)
            self.verticalLayout_light.addItem(spacerItem4)
            self.frame_beam = QtWidgets.QFrame(self.tabWidget_light)
            self.frame_beam.setMaximumSize(QtCore.QSize(370, 16777215))
            self.frame_beam.setFrameShape(QtWidgets.QFrame.Box)
            self.frame_beam.setFrameShadow(QtWidgets.QFrame.Raised)
            self.frame_beam.setObjectName("frame_beam")
            self.formLayout_5 = QtWidgets.QFormLayout(self.frame_beam)
            self.formLayout_5.setObjectName("formLayout_5")
            self.comboBox_light = QtWidgets.QComboBox(self.frame_beam)
            self.comboBox_light.setMaximumSize(QtCore.QSize(100, 16777215))
            self.comboBox_light.setObjectName("comboBox_light")
            self.formLayout_5.setWidget(0, QtWidgets.QFormLayout.SpanningRole, self.comboBox_light)
            self.Qframe_beam_create = QtWidgets.QFrame(self.frame_beam)
            self.Qframe_beam_create.setFrameShape(QtWidgets.QFrame.NoFrame)
            self.Qframe_beam_create.setFrameShadow(QtWidgets.QFrame.Raised)
            self.Qframe_beam_create.setObjectName("Qframe_beam_create")
            self.gridLayout_creat_delete_beam = QtWidgets.QGridLayout(self.Qframe_beam_create)
            self.gridLayout_creat_delete_beam.setObjectName("gridLayout_creat_delete_beam")
            self.pushButton_delete_beam = QtWidgets.QPushButton(self.Qframe_beam_create)
            self.pushButton_delete_beam.setObjectName("pushButton_delete_beam")
            self.gridLayout_creat_delete_beam.addWidget(self.pushButton_delete_beam, 2, 1, 1, 1)
            self.pushButton_create_beam = QtWidgets.QPushButton(self.Qframe_beam_create)
            self.pushButton_create_beam.setObjectName("pushButton_create_beam")
            self.gridLayout_creat_delete_beam.addWidget(self.pushButton_create_beam, 2, 0, 1, 1)
            self.pushButton_save_beam = QtWidgets.QPushButton(self.Qframe_beam_create)
            self.pushButton_save_beam.setObjectName("pushButton_save_beam")
            self.gridLayout_creat_delete_beam.addWidget(self.pushButton_save_beam, 3, 0, 1, 1)
            self.pushButton_cancel_light = QtWidgets.QPushButton(self.Qframe_beam_create)
            self.pushButton_cancel_light.setObjectName("pushButton_cancel_light")
            self.gridLayout_creat_delete_beam.addWidget(self.pushButton_cancel_light, 3, 1, 1, 1)
            self.formLayout_5.setWidget(2, QtWidgets.QFormLayout.SpanningRole, self.Qframe_beam_create)
            self.label_fwhm = QtWidgets.QLabel(self.frame_beam)
            self.label_fwhm.setObjectName("label_fwhm")
            self.formLayout_5.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_fwhm)
            self.doubleSpinBox_fwhm = QtWidgets.QDoubleSpinBox(self.frame_beam)
            self.doubleSpinBox_fwhm.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_fwhm.setDecimals(3)
            self.doubleSpinBox_fwhm.setMaximum(10000.0)
            self.doubleSpinBox_fwhm.setProperty("value", 8.0)
            self.doubleSpinBox_fwhm.setObjectName("doubleSpinBox_fwhm")
            self.formLayout_5.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_fwhm)
            self.checkBox_offset_light = QtWidgets.QCheckBox(self.frame_beam)
            self.checkBox_offset_light.setChecked(True)
            self.checkBox_offset_light.setObjectName("checkBox_offset_light")
            self.formLayout_5.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.checkBox_offset_light)
            self.spinBox_offset_light_peak = QtWidgets.QSpinBox(self.frame_beam)
            self.spinBox_offset_light_peak.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.spinBox_offset_light_peak.setSuffix("")
            self.spinBox_offset_light_peak.setMaximum(10000)
            self.spinBox_offset_light_peak.setProperty("value", 5)
            self.spinBox_offset_light_peak.setObjectName("spinBox_offset_light_peak")
            self.formLayout_5.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.spinBox_offset_light_peak)
            self.label_offset_light = QtWidgets.QLabel(self.frame_beam)
            self.label_offset_light.setObjectName("label_offset_light")
            self.formLayout_5.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_offset_light)
            self.doubleSpinBox_offset_light = QtWidgets.QDoubleSpinBox(self.frame_beam)
            self.doubleSpinBox_offset_light.setEnabled(False)
            self.doubleSpinBox_offset_light.setMinimum(-10000.0)
            self.doubleSpinBox_offset_light.setMaximum(10000.0)
            self.doubleSpinBox_offset_light.setObjectName("doubleSpinBox_offset_light")
            self.formLayout_5.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_offset_light)
            self.label_intensity = QtWidgets.QLabel(self.frame_beam)
            self.label_intensity.setObjectName("label_intensity")
            self.formLayout_5.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_intensity)
            self.doubleSpinBox_intensity_light = QtWidgets.QDoubleSpinBox(self.frame_beam)
            self.doubleSpinBox_intensity_light.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_intensity_light.setDecimals(5)
            self.doubleSpinBox_intensity_light.setMaximum(10000.0)
            self.doubleSpinBox_intensity_light.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType)
            self.doubleSpinBox_intensity_light.setProperty("value", 1.0)
            self.doubleSpinBox_intensity_light.setObjectName("doubleSpinBox_intensity_light")
            self.formLayout_5.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_intensity_light)
            self.radioButton_gaussian_light = QtWidgets.QRadioButton(self.frame_beam)
            self.radioButton_gaussian_light.setEnabled(True)
            self.radioButton_gaussian_light.setChecked(True)
            self.radioButton_gaussian_light.setObjectName("radioButton_gaussian_light")
            self.formLayout_5.setWidget(8, QtWidgets.QFormLayout.SpanningRole, self.radioButton_gaussian_light)
            self.radioButton_squared_light = QtWidgets.QRadioButton(self.frame_beam)
            self.radioButton_squared_light.setChecked(False)
            self.radioButton_squared_light.setObjectName("radioButton_squared_light")
            self.formLayout_5.setWidget(10, QtWidgets.QFormLayout.SpanningRole, self.radioButton_squared_light)
            self.radioButton_mode = QtWidgets.QRadioButton(self.frame_beam)
            self.radioButton_mode.setObjectName("radioButton_mode")
            self.formLayout_5.setWidget(13, QtWidgets.QFormLayout.LabelRole, self.radioButton_mode)
            self.spinBox_mode = QtWidgets.QSpinBox(self.frame_beam)
            self.spinBox_mode.setAutoFillBackground(False)
            self.spinBox_mode.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.spinBox_mode.setMaximum(50)
            self.spinBox_mode.setObjectName("spinBox_mode")
            self.formLayout_5.setWidget(13, QtWidgets.QFormLayout.FieldRole, self.spinBox_mode)
            self.radioButton_all_modes = QtWidgets.QRadioButton(self.frame_beam)
            self.radioButton_all_modes.setObjectName("radioButton_all_modes")
            self.formLayout_5.setWidget(16, QtWidgets.QFormLayout.LabelRole, self.radioButton_all_modes)
            self.radioButton_airy = QtWidgets.QRadioButton(self.frame_beam)
            self.radioButton_airy.setObjectName("radioButton_airy")
            self.formLayout_5.setWidget(19, QtWidgets.QFormLayout.LabelRole, self.radioButton_airy)
            self.label_zero_cut = QtWidgets.QLabel(self.frame_beam)
            self.label_zero_cut.setObjectName("label_zero_cut")
            self.formLayout_5.setWidget(20, QtWidgets.QFormLayout.LabelRole, self.label_zero_cut)
            self.spinBox_airy_zero = QtWidgets.QSpinBox(self.frame_beam)
            self.spinBox_airy_zero.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.spinBox_airy_zero.setMinimum(1)
            self.spinBox_airy_zero.setMaximum(10000)
            self.spinBox_airy_zero.setProperty("value", 10)
            self.spinBox_airy_zero.setObjectName("spinBox_airy_zero")
            self.formLayout_5.setWidget(20, QtWidgets.QFormLayout.FieldRole, self.spinBox_airy_zero)
            self.label_lobe_size = QtWidgets.QLabel(self.frame_beam)
            self.label_lobe_size.setObjectName("label_lobe_size")
            self.formLayout_5.setWidget(21, QtWidgets.QFormLayout.LabelRole, self.label_lobe_size)
            self.doubleSpinBox_lobe_size = QtWidgets.QDoubleSpinBox(self.frame_beam)
            self.doubleSpinBox_lobe_size.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_lobe_size.setMaximum(10000.0)
            self.doubleSpinBox_lobe_size.setProperty("value", 8.0)
            self.doubleSpinBox_lobe_size.setObjectName("doubleSpinBox_lobe_size")
            self.formLayout_5.setWidget(21, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_lobe_size)
            spacerItem5 = QtWidgets.QSpacerItem(20, 5, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
            self.formLayout_5.setItem(18, QtWidgets.QFormLayout.LabelRole, spacerItem5)
            spacerItem6 = QtWidgets.QSpacerItem(20, 5, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
            self.formLayout_5.setItem(12, QtWidgets.QFormLayout.LabelRole, spacerItem6)
            spacerItem7 = QtWidgets.QSpacerItem(20, 5, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
            self.formLayout_5.setItem(7, QtWidgets.QFormLayout.LabelRole, spacerItem7)
            spacerItem8 = QtWidgets.QSpacerItem(20, 5, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
            self.formLayout_5.setItem(15, QtWidgets.QFormLayout.LabelRole, spacerItem8)
            self.pushButton_mode_number = QtWidgets.QPushButton(self.frame_beam)
            self.pushButton_mode_number.setObjectName("pushButton_mode_number")
            self.formLayout_5.setWidget(14, QtWidgets.QFormLayout.LabelRole, self.pushButton_mode_number)
            self.mode_number = QtWidgets.QLCDNumber(self.frame_beam)
            self.mode_number.setMaximumSize(QtCore.QSize(100, 16777215))
            self.mode_number.setObjectName("mode_number")
            self.formLayout_5.setWidget(14, QtWidgets.QFormLayout.FieldRole, self.mode_number)
            spacerItem9 = QtWidgets.QSpacerItem(20, 5, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
            self.formLayout_5.setItem(9, QtWidgets.QFormLayout.LabelRole, spacerItem9)
            self.verticalLayout_light.addWidget(self.frame_beam)
            spacerItem10 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum)
            self.verticalLayout_light.addItem(spacerItem10)
            self.calculateButton_light = QtWidgets.QPushButton(self.tabWidget_light)
            self.calculateButton_light.setMaximumSize(QtCore.QSize(370, 16777215))
            self.calculateButton_light.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
            self.calculateButton_light.setObjectName("calculateButton_light")
            self.verticalLayout_light.addWidget(self.calculateButton_light)
            spacerItem11 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
            self.verticalLayout_light.addItem(spacerItem11)
            self.horizontalLayout_4.addLayout(self.verticalLayout_light)
            self.plot_light = QtWidgets.QVBoxLayout()
            self.plot_light.setObjectName("plot_light")
            self.horizontalLayout_4.addLayout(self.plot_light)
            self.tabWidget_main.addTab(self.tabWidget_light, "")
            self.tabWidget_compute = QtWidgets.QWidget()
            self.tabWidget_compute.setObjectName("tabWidget_compute")
            self.horizontalLayout = QtWidgets.QHBoxLayout(self.tabWidget_compute)
            self.horizontalLayout.setObjectName("horizontalLayout")
            self.verticalLayout_compute_plot = QtWidgets.QVBoxLayout()
            self.verticalLayout_compute_plot.setObjectName("verticalLayout_compute_plot")
            self.verticalLayout_compute = QtWidgets.QVBoxLayout()
            self.verticalLayout_compute.setObjectName("verticalLayout_compute")
            self.label_lost_informations = QtWidgets.QLabel(self.tabWidget_compute)
            self.label_lost_informations.setMinimumSize(QtCore.QSize(0, 62))
            self.label_lost_informations.setMouseTracking(True)
            self.label_lost_informations.setObjectName("label_lost_informations")
            self.verticalLayout_compute.addWidget(self.label_lost_informations)
            self.checkBox_lost = QtWidgets.QCheckBox(self.tabWidget_compute)
            self.checkBox_lost.setEnabled(True)
            self.checkBox_lost.setCheckable(True)
            self.checkBox_lost.setChecked(False)
            self.checkBox_lost.setObjectName("checkBox_lost")
            self.verticalLayout_compute.addWidget(self.checkBox_lost)
            self.frame_lost = QtWidgets.QFrame(self.tabWidget_compute)
            self.frame_lost.setEnabled(False)
            self.frame_lost.setMinimumSize(QtCore.QSize(370, 0))
            self.frame_lost.setMaximumSize(QtCore.QSize(370, 16777215))
            self.frame_lost.setFrameShape(QtWidgets.QFrame.Box)
            self.frame_lost.setFrameShadow(QtWidgets.QFrame.Raised)
            self.frame_lost.setObjectName("frame_lost")
            self.formLayout_8 = QtWidgets.QFormLayout(self.frame_lost)
            self.formLayout_8.setObjectName("formLayout_8")
            self.label_guide_lost = QtWidgets.QLabel(self.frame_lost)
            self.label_guide_lost.setObjectName("label_guide_lost")
            self.formLayout_8.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_guide_lost)
            self.spinBox_guide_lost = QtWidgets.QSpinBox(self.frame_lost)
            self.spinBox_guide_lost.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.spinBox_guide_lost.setMaximum(1000)
            self.spinBox_guide_lost.setObjectName("spinBox_guide_lost")
            self.formLayout_8.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.spinBox_guide_lost)
            self.label_width_lost = QtWidgets.QLabel(self.frame_lost)
            self.label_width_lost.setObjectName("label_width_lost")
            self.formLayout_8.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_width_lost)
            self.doubleSpinBox_width_lost = QtWidgets.QDoubleSpinBox(self.frame_lost)
            self.doubleSpinBox_width_lost.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_width_lost.setDecimals(3)
            self.doubleSpinBox_width_lost.setMaximum(10000.0)
            self.doubleSpinBox_width_lost.setProperty("value", 10.0)
            self.doubleSpinBox_width_lost.setObjectName("doubleSpinBox_width_lost")
            self.formLayout_8.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_width_lost)
            self.label_lost = QtWidgets.QLabel(self.frame_lost)
            self.label_lost.setObjectName("label_lost")
            self.formLayout_8.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_lost)
            self.doubleSpinBox_lost = QtWidgets.QDoubleSpinBox(self.frame_lost)
            self.doubleSpinBox_lost.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_lost.setDecimals(5)
            self.doubleSpinBox_lost.setMaximum(10000.0)
            self.doubleSpinBox_lost.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType)
            self.doubleSpinBox_lost.setProperty("value", 1.0)
            self.doubleSpinBox_lost.setObjectName("doubleSpinBox_lost")
            self.formLayout_8.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_lost)
            self.verticalLayout_compute.addWidget(self.frame_lost)
            spacerItem12 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum)
            self.verticalLayout_compute.addItem(spacerItem12)
            self.label_kerr_informations = QtWidgets.QLabel(self.tabWidget_compute)
            self.label_kerr_informations.setMinimumSize(QtCore.QSize(0, 62))
            self.label_kerr_informations.setMouseTracking(True)
            self.label_kerr_informations.setObjectName("label_kerr_informations")
            self.verticalLayout_compute.addWidget(self.label_kerr_informations)
            self.checkBox_kerr = QtWidgets.QCheckBox(self.tabWidget_compute)
            self.checkBox_kerr.setEnabled(True)
            self.checkBox_kerr.setChecked(False)
            self.checkBox_kerr.setObjectName("checkBox_kerr")
            self.verticalLayout_compute.addWidget(self.checkBox_kerr)
            self.frame_kerr = QtWidgets.QFrame(self.tabWidget_compute)
            self.frame_kerr.setEnabled(False)
            self.frame_kerr.setMinimumSize(QtCore.QSize(370, 0))
            self.frame_kerr.setMaximumSize(QtCore.QSize(370, 16777215))
            self.frame_kerr.setFrameShape(QtWidgets.QFrame.Box)
            self.frame_kerr.setFrameShadow(QtWidgets.QFrame.Raised)
            self.frame_kerr.setObjectName("frame_kerr")
            self.formLayout_9 = QtWidgets.QFormLayout(self.frame_kerr)
            self.formLayout_9.setObjectName("formLayout_9")
            self.label_correction_loop = QtWidgets.QLabel(self.frame_kerr)
            self.label_correction_loop.setObjectName("label_correction_loop")
            self.formLayout_9.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_correction_loop)
            self.spinBox_kerr_loop = QtWidgets.QSpinBox(self.frame_kerr)
            self.spinBox_kerr_loop.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.spinBox_kerr_loop.setMinimum(1)
            self.spinBox_kerr_loop.setMaximum(100)
            self.spinBox_kerr_loop.setProperty("value", 2)
            self.spinBox_kerr_loop.setObjectName("spinBox_kerr_loop")
            self.formLayout_9.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.spinBox_kerr_loop)
            self.label_chi3 = QtWidgets.QLabel(self.frame_kerr)
            self.label_chi3.setObjectName("label_chi3")
            self.formLayout_9.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_chi3)
            self.doubleSpinBox_chi3 = QtWidgets.QDoubleSpinBox(self.frame_kerr)
            self.doubleSpinBox_chi3.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectToNearestValue)
            self.doubleSpinBox_chi3.setMaximum(100000.0)
            self.doubleSpinBox_chi3.setProperty("value", 10.0)
            self.doubleSpinBox_chi3.setObjectName("doubleSpinBox_chi3")
            self.formLayout_9.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_chi3)
            self.checkBox_variance = QtWidgets.QCheckBox(self.frame_kerr)
            self.checkBox_variance.setEnabled(False)
            self.checkBox_variance.setObjectName("checkBox_variance")
            self.formLayout_9.setWidget(3, QtWidgets.QFormLayout.SpanningRole, self.checkBox_variance)
            self.verticalLayout_compute.addWidget(self.frame_kerr)
            self.formLayout_estimate = QtWidgets.QFormLayout()
            self.formLayout_estimate.setObjectName("formLayout_estimate")
            self.estimate_time_display = QtWidgets.QLCDNumber(self.tabWidget_compute)
            self.estimate_time_display.setEnabled(True)
            self.estimate_time_display.setMinimumSize(QtCore.QSize(100, 0))
            self.estimate_time_display.setMaximumSize(QtCore.QSize(100, 16777215))
            self.estimate_time_display.setDigitCount(3)
            self.estimate_time_display.setSegmentStyle(QtWidgets.QLCDNumber.Filled)
            self.estimate_time_display.setObjectName("estimate_time_display")
            self.formLayout_estimate.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.estimate_time_display)
            self.pushButton_estimate_time = QtWidgets.QPushButton(self.tabWidget_compute)
            self.pushButton_estimate_time.setMinimumSize(QtCore.QSize(150, 0))
            self.pushButton_estimate_time.setMaximumSize(QtCore.QSize(150, 16777215))
            self.pushButton_estimate_time.setObjectName("pushButton_estimate_time")
            self.formLayout_estimate.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.pushButton_estimate_time)
            self.verticalLayout_compute.addLayout(self.formLayout_estimate)
            spacerItem13 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum)
            self.verticalLayout_compute.addItem(spacerItem13)
            self.calculateButton_compute = QtWidgets.QPushButton(self.tabWidget_compute)
            self.calculateButton_compute.setMinimumSize(QtCore.QSize(370, 0))
            self.calculateButton_compute.setMaximumSize(QtCore.QSize(370, 16777215))
            self.calculateButton_compute.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
            self.calculateButton_compute.setObjectName("calculateButton_compute")
            self.verticalLayout_compute.addWidget(self.calculateButton_compute)
            self.checkBox_check_power = QtWidgets.QCheckBox(self.tabWidget_compute)
            self.checkBox_check_power.setObjectName("checkBox_check_power")
            self.verticalLayout_compute.addWidget(self.checkBox_check_power)
            spacerItem14 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
            self.verticalLayout_compute.addItem(spacerItem14)
            self.verticalLayout_compute_plot.addLayout(self.verticalLayout_compute)
            self.pushButton_cancel_compute = QtWidgets.QPushButton(self.tabWidget_compute)
            self.pushButton_cancel_compute.setMaximumSize(QtCore.QSize(100, 16777215))
            self.pushButton_cancel_compute.setObjectName("pushButton_cancel_compute")
            self.verticalLayout_compute_plot.addWidget(self.pushButton_cancel_compute)
            self.horizontalLayout.addLayout(self.verticalLayout_compute_plot)
            self.plot_compute = QtWidgets.QVBoxLayout()
            self.plot_compute.setObjectName("plot_compute")
            self.horizontalLayout.addLayout(self.plot_compute)
            self.tabWidget_main.addTab(self.tabWidget_compute, "")
            self.verticalLayout.addWidget(self.tabWidget_main)
            self.gridLayout.addWidget(self.frame_file_data, 0, 1, 1, 1)
            MainWindow.setCentralWidget(self.centralwidget)
            self.label_length.setBuddy(self.frame_light)

            self.retranslateUi(MainWindow)
            self.tabWidget_main.setCurrentIndex(0)
            self.tabWidget_morphology_guide.setCurrentIndex(0)
            self.checkBox_offset_light.clicked['bool'].connect(self.doubleSpinBox_offset_light.setDisabled)
            self.checkBox_kerr.clicked['bool'].connect(self.frame_kerr.setEnabled)
            self.checkBox_offset_light.clicked['bool'].connect(self.spinBox_offset_light_peak.setEnabled)
            self.checkBox_lost.clicked['bool'].connect(self.frame_lost.setEnabled)
            self.checkBox_kerr.clicked['bool'].connect(self.checkBox_variance.setEnabled)
            self.comboBox_light.activated['QString'].connect(self.pushButton_cancel_light.click)
            QtCore.QMetaObject.connectSlotsByName(MainWindow)
            MainWindow.setTabOrder(self.tabWidget_main, self.doubleSpinBox_length_z)
            MainWindow.setTabOrder(self.doubleSpinBox_length_z, self.doubleSpinBox_dist_z)
            MainWindow.setTabOrder(self.doubleSpinBox_dist_z, self.spinBox_nbr_z_disp)
            MainWindow.setTabOrder(self.spinBox_nbr_z_disp, self.doubleSpinBox_length_x)
            MainWindow.setTabOrder(self.doubleSpinBox_length_x, self.doubleSpinBox_dist_x)
            MainWindow.setTabOrder(self.doubleSpinBox_dist_x, self.doubleSpinBox_width)
            MainWindow.setTabOrder(self.doubleSpinBox_width, self.doubleSpinBox_offset_guide)
            MainWindow.setTabOrder(self.doubleSpinBox_offset_guide, self.doubleSpinBox_n)
            MainWindow.setTabOrder(self.doubleSpinBox_n, self.doubleSpinBox_dn)
            MainWindow.setTabOrder(self.doubleSpinBox_dn, self.radioButton_gaussian)
            MainWindow.setTabOrder(self.radioButton_gaussian, self.spinBox_gauss_pow)
            MainWindow.setTabOrder(self.spinBox_gauss_pow, self.radioButton_squared)
            MainWindow.setTabOrder(self.radioButton_squared, self.tabWidget_morphology_guide)
            MainWindow.setTabOrder(self.tabWidget_morphology_guide, self.spinBox_nb_p)
            MainWindow.setTabOrder(self.spinBox_nb_p, self.doubleSpinBox_p)
            MainWindow.setTabOrder(self.doubleSpinBox_p, self.calculateButton_array)
            MainWindow.setTabOrder(self.calculateButton_array, self.doubleSpinBox_curve)
            MainWindow.setTabOrder(self.doubleSpinBox_curve, self.doubleSpinBox_half_delay)
            MainWindow.setTabOrder(self.doubleSpinBox_half_delay, self.doubleSpinBox_distance_factor)
            MainWindow.setTabOrder(self.doubleSpinBox_distance_factor, self.calculateButton_curved)
            MainWindow.setTabOrder(self.calculateButton_curved, self.pushButton_cancel_guide)
            MainWindow.setTabOrder(self.pushButton_cancel_guide, self.doubleSpinBox_lo)
            MainWindow.setTabOrder(self.doubleSpinBox_lo, self.doubleSpinBox_theta_ext)
            MainWindow.setTabOrder(self.doubleSpinBox_theta_ext, self.comboBox_light)
            MainWindow.setTabOrder(self.comboBox_light, self.pushButton_create_beam)
            MainWindow.setTabOrder(self.pushButton_create_beam, self.pushButton_delete_beam)
            MainWindow.setTabOrder(self.pushButton_delete_beam, self.pushButton_save_beam)
            MainWindow.setTabOrder(self.pushButton_save_beam, self.pushButton_cancel_light)
            MainWindow.setTabOrder(self.pushButton_cancel_light, self.doubleSpinBox_fwhm)
            MainWindow.setTabOrder(self.doubleSpinBox_fwhm, self.checkBox_offset_light)
            MainWindow.setTabOrder(self.checkBox_offset_light, self.spinBox_offset_light_peak)
            MainWindow.setTabOrder(self.spinBox_offset_light_peak, self.doubleSpinBox_offset_light)
            MainWindow.setTabOrder(self.doubleSpinBox_offset_light, self.doubleSpinBox_intensity_light)
            MainWindow.setTabOrder(self.doubleSpinBox_intensity_light, self.radioButton_gaussian_light)
            MainWindow.setTabOrder(self.radioButton_gaussian_light, self.radioButton_squared_light)
            MainWindow.setTabOrder(self.radioButton_squared_light, self.radioButton_mode)
            MainWindow.setTabOrder(self.radioButton_mode, self.spinBox_mode)
            MainWindow.setTabOrder(self.spinBox_mode, self.pushButton_mode_number)
            MainWindow.setTabOrder(self.pushButton_mode_number, self.radioButton_all_modes)
            MainWindow.setTabOrder(self.radioButton_all_modes, self.radioButton_airy)
            MainWindow.setTabOrder(self.radioButton_airy, self.spinBox_airy_zero)
            MainWindow.setTabOrder(self.spinBox_airy_zero, self.doubleSpinBox_lobe_size)
            MainWindow.setTabOrder(self.doubleSpinBox_lobe_size, self.calculateButton_light)
            MainWindow.setTabOrder(self.calculateButton_light, self.checkBox_lost)
            MainWindow.setTabOrder(self.checkBox_lost, self.spinBox_guide_lost)
            MainWindow.setTabOrder(self.spinBox_guide_lost, self.doubleSpinBox_width_lost)
            MainWindow.setTabOrder(self.doubleSpinBox_width_lost, self.doubleSpinBox_lost)
            MainWindow.setTabOrder(self.doubleSpinBox_lost, self.checkBox_kerr)
            MainWindow.setTabOrder(self.checkBox_kerr, self.spinBox_kerr_loop)
            MainWindow.setTabOrder(self.spinBox_kerr_loop, self.doubleSpinBox_chi3)
            MainWindow.setTabOrder(self.doubleSpinBox_chi3, self.checkBox_variance)
            MainWindow.setTabOrder(self.checkBox_variance, self.pushButton_estimate_time)
            MainWindow.setTabOrder(self.pushButton_estimate_time, self.calculateButton_compute)
            MainWindow.setTabOrder(self.calculateButton_compute, self.checkBox_check_power)
            MainWindow.setTabOrder(self.checkBox_check_power, self.pushButton_cancel_compute)

        def retranslateUi(self, MainWindow):
            _translate = QtCore.QCoreApplication.translate
            MainWindow.setWindowTitle(_translate("MainWindow", "Beampy"))
            self.label_window_parameters.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-size:14pt; font-weight:600;\">Window information</span></p></body></html>"))
            self.label_length.setToolTip(_translate("MainWindow", "Size of the computed window over z"))
            self.label_length.setText(_translate("MainWindow", "z length"))
            self.doubleSpinBox_length_z.setToolTip(_translate("MainWindow", "Size of the computed window over z"))
            self.doubleSpinBox_length_z.setSuffix(_translate("MainWindow", " µm"))
            self.label_dist_z.setToolTip(_translate("MainWindow", "Step over z in µm"))
            self.label_dist_z.setText(_translate("MainWindow", "z step"))
            self.doubleSpinBox_dist_z.setToolTip(_translate("MainWindow", "Step over z in µm"))
            self.doubleSpinBox_dist_z.setSuffix(_translate("MainWindow", " µm"))
            self.label_nbr_z_disp.setToolTip(_translate("MainWindow", "Number of points to display over z"))
            self.label_nbr_z_disp.setText(_translate("MainWindow", "z nbr displayed"))
            self.spinBox_nbr_z_disp.setToolTip(_translate("MainWindow", "Number of points to display over z"))
            self.label_length_x.setToolTip(_translate("MainWindow", "Size of the compute window over x in µm"))
            self.label_length_x.setText(_translate("MainWindow", "x length"))
            self.doubleSpinBox_length_x.setToolTip(_translate("MainWindow", "Size of the compute window over x in µm"))
            self.doubleSpinBox_length_x.setSuffix(_translate("MainWindow", " µm"))
            self.label_dist_x.setToolTip(_translate("MainWindow", "Step over x in µm"))
            self.label_dist_x.setText(_translate("MainWindow", "x step"))
            self.doubleSpinBox_dist_x.setToolTip(_translate("MainWindow", "Step over x in µm"))
            self.doubleSpinBox_dist_x.setSuffix(_translate("MainWindow", " µm"))
            self.label_guides_information.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-size:14pt; font-weight:600;\">Guides information</span></p></body></html>"))
            self.label_width.setToolTip(_translate("MainWindow", "Guide width define as the diameter in µm at 1/e"))
            self.label_width.setText(_translate("MainWindow", "Width"))
            self.doubleSpinBox_width.setToolTip(_translate("MainWindow", "Guide width define as the diameter in µm at 1/e"))
            self.doubleSpinBox_width.setSuffix(_translate("MainWindow", " μm"))
            self.label_offset_guide.setToolTip(_translate("MainWindow", "Guide offset from the center in µm"))
            self.label_offset_guide.setText(_translate("MainWindow", "Guide offset"))
            self.doubleSpinBox_offset_guide.setToolTip(_translate("MainWindow", "Guide offset from the center in µm"))
            self.doubleSpinBox_offset_guide.setSuffix(_translate("MainWindow", " µm"))
            self.doubleSpinBox_n.setToolTip(_translate("MainWindow", "Refractive index of the cladding"))
            self.label_n.setToolTip(_translate("MainWindow", "Refractive index of the cladding"))
            self.label_n.setText(_translate("MainWindow", "n"))
            self.label_dn.setToolTip(_translate("MainWindow", "Difference of refractive index between the core and the cladding"))
            self.label_dn.setText(_translate("MainWindow", "Δn"))
            self.doubleSpinBox_dn.setToolTip(_translate("MainWindow", "Difference of refractive index between the core and the cladding"))
            self.radioButton_gaussian.setToolTip(_translate("MainWindow", "Choose super-gaussian guides"))
            self.radioButton_gaussian.setText(_translate("MainWindow", "Gaussian"))
            self.spinBox_gauss_pow.setToolTip(_translate("MainWindow", "Order of the super-Gaussian beam, 1 is gaussian, 4 is the usual super-Gaussian"))
            self.spinBox_gauss_pow.setPrefix(_translate("MainWindow", "order: "))
            self.radioButton_squared.setToolTip(_translate("MainWindow", "Choose squared guides"))
            self.radioButton_squared.setText(_translate("MainWindow", "Squared"))
            self.label_nb_p.setToolTip(_translate("MainWindow", "Number of guides"))
            self.label_nb_p.setText(_translate("MainWindow", "Numbers of guides"))
            self.spinBox_nb_p.setToolTip(_translate("MainWindow", "Number of guides"))
            self.label_p.setToolTip(_translate("MainWindow", "Distance between two guides center in µm"))
            self.label_p.setText(_translate("MainWindow", "Interval between guides"))
            self.doubleSpinBox_p.setToolTip(_translate("MainWindow", "Distance between two guides center in µm"))
            self.doubleSpinBox_p.setSuffix(_translate("MainWindow", " µm"))
            self.calculateButton_array.setToolTip(_translate("MainWindow", "Compute an array of guides"))
            self.calculateButton_array.setText(_translate("MainWindow", "Compute array of guides"))
            self.tabWidget_morphology_guide.setTabText(self.tabWidget_morphology_guide.indexOf(self.tab_array), _translate("MainWindow", "waveguide array"))
            self.label_curve.setToolTip(_translate("MainWindow", "curvature factor in 10^-8 1/µm^2"))
            self.label_curve.setText(_translate("MainWindow", "Curvature"))
            self.doubleSpinBox_curve.setToolTip(_translate("MainWindow", "curvature factor in 10^-8 1/µm^2"))
            self.doubleSpinBox_curve.setSuffix(_translate("MainWindow", " * 10^-8 1/µm^2"))
            self.label_half_delay.setToolTip(_translate("MainWindow", "Half distance over z in µm bewteen the two external guides where they are the closest"))
            self.label_half_delay.setText(_translate("MainWindow", "Half delay"))
            self.doubleSpinBox_half_delay.setToolTip(_translate("MainWindow", "Half distance over z in µm bewteen the two external guides where they are the closest"))
            self.doubleSpinBox_half_delay.setSuffix(_translate("MainWindow", " µm"))
            self.label_distance_factor.setToolTip(_translate("MainWindow", "Distance factor: p_min/width"))
            self.label_distance_factor.setText(_translate("MainWindow", "p_min/width"))
            self.doubleSpinBox_distance_factor.setToolTip(_translate("MainWindow", "Distance factor: p_min/width"))
            self.doubleSpinBox_distance_factor.setSuffix(_translate("MainWindow", " µm"))
            self.calculateButton_curved.setToolTip(_translate("MainWindow", "Compute the curved guides define as : - offset_guide + curve*(z - length_z/2 - half_delay)**2 + width*distance_factor)"))
            self.calculateButton_curved.setText(_translate("MainWindow", "Compute curved guides"))
            self.tabWidget_morphology_guide.setTabText(self.tabWidget_morphology_guide.indexOf(self.tab_curved), _translate("MainWindow", "curved waveguides"))
            self.pushButton_cancel_guide.setToolTip(_translate("MainWindow", "cancel guide changes"))
            self.pushButton_cancel_guide.setText(_translate("MainWindow", "Cancel changes"))
            self.tabWidget_main.setTabText(self.tabWidget_main.indexOf(self.tabWidget_guide), _translate("MainWindow", "Guides"))
            self.label_light_informations.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-size:14pt; font-weight:600;\">Light information</span></p></body></html>"))
            self.label_lo.setToolTip(_translate("MainWindow", " Wavelengh in µm"))
            self.label_lo.setText(_translate("MainWindow", "λ"))
            self.doubleSpinBox_lo.setToolTip(_translate("MainWindow", " Wavelengh in µm"))
            self.doubleSpinBox_lo.setSuffix(_translate("MainWindow", " µm"))
            self.label_theta_ext.setToolTip(_translate("MainWindow", "Number of the last mode that can propagate in the guide"))
            self.label_theta_ext.setText(_translate("MainWindow", "θ ext"))
            self.doubleSpinBox_theta_ext.setToolTip(_translate("MainWindow", "Exterior inclinaison angle in ° define from a interface between air and the cladding"))
            self.doubleSpinBox_theta_ext.setSuffix(_translate("MainWindow", " °"))
            self.comboBox_light.setToolTip(_translate("MainWindow", "Select the beam"))
            self.pushButton_delete_beam.setToolTip(_translate("MainWindow", "Delete the current displayed beam"))
            self.pushButton_delete_beam.setText(_translate("MainWindow", "delete beam"))
            self.pushButton_create_beam.setToolTip(_translate("MainWindow", "Add a new beam with current displayed values"))
            self.pushButton_create_beam.setText(_translate("MainWindow", "create beam"))
            self.pushButton_save_beam.setToolTip(_translate("MainWindow", "Save current displayed values"))
            self.pushButton_save_beam.setText(_translate("MainWindow", "save beam"))
            self.pushButton_cancel_light.setToolTip(_translate("MainWindow", "Return to previously saved values"))
            self.pushButton_cancel_light.setText(_translate("MainWindow", "cancel changes"))
            self.label_fwhm.setToolTip(_translate("MainWindow", "Full width at half maximum (for intensity not amplitude)"))
            self.label_fwhm.setText(_translate("MainWindow", "FWHM"))
            self.doubleSpinBox_fwhm.setToolTip(_translate("MainWindow", "Full width at half maximum (for intensity not amplitude)"))
            self.doubleSpinBox_fwhm.setSuffix(_translate("MainWindow", " μm"))
            self.checkBox_offset_light.setToolTip(_translate("MainWindow", "Choose if offset is define by the guides positions or by the distance from center"))
            self.checkBox_offset_light.setText(_translate("MainWindow", "Offset (number)"))
            self.spinBox_offset_light_peak.setToolTip(_translate("MainWindow", "Offset define by the guide position"))
            self.spinBox_offset_light_peak.setPrefix(_translate("MainWindow", "Guide number : "))
            self.label_offset_light.setToolTip(_translate("MainWindow", "Light offset from center"))
            self.label_offset_light.setText(_translate("MainWindow", "Offset (µm)"))
            self.doubleSpinBox_offset_light.setToolTip(_translate("MainWindow", "Light offset from center in µm"))
            self.doubleSpinBox_offset_light.setSuffix(_translate("MainWindow", " µm"))
            self.label_intensity.setToolTip(_translate("MainWindow", "Beam power"))
            self.label_intensity.setText(_translate("MainWindow", "Beam power"))
            self.doubleSpinBox_intensity_light.setToolTip(_translate("MainWindow", "Beam power |E|^2 in GW/cm^2"))
            self.doubleSpinBox_intensity_light.setSuffix(_translate("MainWindow", " GW/cm^2"))
            self.radioButton_gaussian_light.setToolTip(_translate("MainWindow", "Select a gaussian beam"))
            self.radioButton_gaussian_light.setText(_translate("MainWindow", "Gaussian"))
            self.radioButton_squared_light.setToolTip(_translate("MainWindow", "Select a squared beam"))
            self.radioButton_squared_light.setText(_translate("MainWindow", "Squared"))
            self.radioButton_mode.setToolTip(_translate("MainWindow", "select the n mode based on a squared guide"))
            self.radioButton_mode.setText(_translate("MainWindow", "Mode"))
            self.spinBox_mode.setToolTip(_translate("MainWindow", "The n mode based on a squared guide"))
            self.radioButton_all_modes.setToolTip(_translate("MainWindow", "Select all possible modes for a squared guide"))
            self.radioButton_all_modes.setText(_translate("MainWindow", "All modes"))
            self.radioButton_airy.setToolTip(_translate("MainWindow", "Select a Airy beam"))
            self.radioButton_airy.setText(_translate("MainWindow", "Airy"))
            self.label_zero_cut.setToolTip(_translate("MainWindow", "Choose to cut at the n zero of the Airy function"))
            self.label_zero_cut.setText(_translate("MainWindow", "Zero cut"))
            self.spinBox_airy_zero.setToolTip(_translate("MainWindow", "Choose to cut at the n zero of the Airy function"))
            self.label_lobe_size.setText(_translate("MainWindow", "First lobe size"))
            self.doubleSpinBox_lobe_size.setSuffix(_translate("MainWindow", " µm"))
            self.pushButton_mode_number.setToolTip(_translate("MainWindow", "Displayed the number of the last mode that can propagate in the rectangular guide"))
            self.pushButton_mode_number.setText(_translate("MainWindow", "Show max mode"))
            self.mode_number.setToolTip(_translate("MainWindow", "Number of the last mode that can propagate in the guide"))
            self.calculateButton_light.setToolTip(_translate("MainWindow", "Compute the beams"))
            self.calculateButton_light.setText(_translate("MainWindow", "Compute light"))
            self.tabWidget_main.setTabText(self.tabWidget_main.indexOf(self.tabWidget_light), _translate("MainWindow", "Light"))
            self.label_lost_informations.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-size:14pt; font-weight:600;\">Loss information</span></p></body></html>"))
            self.checkBox_lost.setToolTip(_translate("MainWindow", "Activate looses in guides"))
            self.checkBox_lost.setText(_translate("MainWindow", "activate looses"))
            self.label_guide_lost.setToolTip(_translate("MainWindow", "Guide number where looses occure"))
            self.label_guide_lost.setText(_translate("MainWindow", "Lost position"))
            self.spinBox_guide_lost.setToolTip(_translate("MainWindow", "Guide number where looses occure"))
            self.label_width_lost.setToolTip(_translate("MainWindow", "Interval where looses occures centered on the guide"))
            self.label_width_lost.setText(_translate("MainWindow", "Lost width"))
            self.doubleSpinBox_width_lost.setToolTip(_translate("MainWindow", "Interval where looses occures centered on the guide"))
            self.doubleSpinBox_width_lost.setSuffix(_translate("MainWindow", " µm"))
            self.label_lost.setToolTip(_translate("MainWindow", "Looses over z in 1/mm define as exp(-alpha * dist_z)"))
            self.label_lost.setText(_translate("MainWindow", "Lost value"))
            self.doubleSpinBox_lost.setToolTip(_translate("MainWindow", "Looses over z in 1/mm define as exp(-alpha * dist_z)"))
            self.doubleSpinBox_lost.setSuffix(_translate("MainWindow", " 1/mm"))
            self.label_kerr_informations.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-size:14pt; font-weight:600;\">Kerr information</span></p></body></html>"))
            self.checkBox_kerr.setToolTip(_translate("MainWindow", "Activate the non-linear effect: Kerr effect"))
            self.checkBox_kerr.setText(_translate("MainWindow", "Kerr effect"))
            self.label_correction_loop.setText(_translate("MainWindow", "Correction"))
            self.spinBox_kerr_loop.setToolTip(_translate("MainWindow", "Number of corrective loop for the Kerr effect"))
            self.spinBox_kerr_loop.setSuffix(_translate("MainWindow", " loops"))
            self.label_chi3.setToolTip(_translate("MainWindow", "The X(3) Electric susceptibility of the material"))
            self.label_chi3.setText(_translate("MainWindow", "Chi3"))
            self.doubleSpinBox_chi3.setToolTip(_translate("MainWindow", "The X(3) Electric susceptibility of the material"))
            self.doubleSpinBox_chi3.setSuffix(_translate("MainWindow", " * 10^-20 m^2/V^2"))
            self.checkBox_variance.setToolTip(_translate("MainWindow", "Use this control to make sure the intensities converge, but increase drasticly the computation time"))
            self.checkBox_variance.setText(_translate("MainWindow", "Check if intensities converge (slow)"))
            self.estimate_time_display.setToolTip(_translate("MainWindow", "Displayed the estimation time needed to do the propagation"))
            self.estimate_time_display.setStatusTip(_translate("MainWindow", "Show the estimate computation time"))
            self.pushButton_estimate_time.setToolTip(_translate("MainWindow", "When pressed, displayed the estimation time needed to do the propagation"))
            self.pushButton_estimate_time.setText(_translate("MainWindow", "Show estimate time (s)"))
            self.calculateButton_compute.setToolTip(_translate("MainWindow", "Compute beam propagation"))
            self.calculateButton_compute.setText(_translate("MainWindow", "Calculate"))
            self.checkBox_check_power.setToolTip(_translate("MainWindow", "Display the power in each guide as power=sum(I(x))"))
            self.checkBox_check_power.setText(_translate("MainWindow", "Display power"))
            self.pushButton_cancel_compute.setText(_translate("MainWindow", "Cancel changes"))
            self.tabWidget_main.setTabText(self.tabWidget_main.indexOf(self.tabWidget_compute), _translate("MainWindow", "Compute"))

    if __name__ == "__main__":
        import sys
        app = QtWidgets.QApplication(sys.argv)
        MainWindow = QtWidgets.QMainWindow()
        ui = Ui_MainWindow()
        ui.setupUi(MainWindow)
        MainWindow.show()
        sys.exit(app.exec_())

## beampy.user_interface

    """
    The user_interface module is the main file of the beampy module.
    It contain the UserInterface class used to computed and displayed the bpm
    results onto the interface.

    This module was at first developed by Marcel Soubkovsky for the implementation
    of the array of guides, of one gaussian beam and of the plotting methods.
    Then, continued by Jonathan Peltier.
    """
    import sys
    import os
    import webbrowser
    import time
    import numpy as np

    from PyQt5.QtWidgets import (QApplication, QMainWindow, QFileDialog)
    from PyQt5.QtCore import (pyqtSlot, Qt, QSize)
    from PyQt5.QtGui import QIcon

    from matplotlib.figure import Figure
    from matplotlib.backends.backend_qt4agg import (
        FigureCanvasQTAgg as FigureCanvas,
        NavigationToolbar2QT as NavigationToolbar)
    from matplotlib import lines
    from matplotlib.patches import Polygon

    # interface.py generated from interface.ui made using Qt designer
    from beampy.interface import Ui_MainWindow
    from beampy.bpm import Bpm  # Bpm class with all the BPM methods

    # ! To translate from .ui to .py -> pyuic5 -x interface.ui -o interface.py

    # Check out if doubts on the interface:
    # http://blog.rcnelson.com/building-a-matplotlib-gui-with-qt-designer-part-1/

    class UserInterface(QMainWindow, Ui_MainWindow):
        """
        This class connect the :class:`.Bpm` class from the :mod:`.bpm` module
        with the :meth:`.setupUi` method from the :mod:`.interface` module.
        """

        def __init__(self):
            QMainWindow.__init__(self)
            self.setupUi(self)  # Linked to Ui_MainWindow through interface.py

            # Prepare variables before assigning values to them
            self.fwhm = []
            self.offset_light = []
            self.irrad = []
            self.offset_check = []
            self.gaussian_check = []
            self.square_check = []
            self.mode_check = []
            self.all_modes_check = []
            self.mode = np.array([], dtype=int)
            self.offset_light_peak = np.array([], dtype=int)
            self.airy_check = []
            self.airy_zero = np.array([], dtype=int)
            self.lobe_size = []
            self.previous_beam = 0

            self.on_click_create_light()  # Initialized variables with buttons

            self.calculate_guide('array')  # Compute guide
            self.calculate_light()  # Compute light

            self.addmpl('guide')  # Display guide
            self.addmpl('light')  # Display light

            self.show_estimate_time()

            # Initialized compute graphics
            self.canvas_compute_propag = FigureCanvas(Figure())
            self.plot_compute.addWidget(self.canvas_compute_propag)
            self.toolbar_3 = FigureCanvas(Figure())
            self.plot_compute.addWidget(self.toolbar_3)
            self.toolbar_3.close()
            self.canvas_5 = FigureCanvas(Figure())
            self.verticalLayout_compute_plot.addWidget(self.canvas_5)
            self.toolbar_5 = FigureCanvas(Figure())
            self.verticalLayout_compute_plot.addWidget(self.toolbar_5)
            self.canvas_compute_end = FigureCanvas(Figure())
            self.plot_compute.addWidget(self.canvas_compute_end)
            self.toolbar_4 = FigureCanvas(Figure())
            self.plot_compute.addWidget(self.toolbar_4)

            self.filename = None

            self.connect_buttons()
            self.create_menu()

        def connect_buttons(self):
            """
            Connect the interface buttons to their corresponding functions:

            :meth:`.on_click_array`, :meth:`.on_click_curved`,
            :meth:`.on_click_light`, :meth:`.on_click_compute`,
            :meth:`.on_click_create_light`, :meth:`.on_click_delete_light`,
            :meth:`.save_light`, :meth:`.get_guide`,
            :meth:`.get_light`, :meth:`.get_compute`,
            :meth:`.show_estimate_time`, :meth:`.check_modes_display`.
            """
            self.calculateButton_array.clicked.connect(self.on_click_array)
            self.calculateButton_curved.clicked.connect(self.on_click_curved)
            self.calculateButton_light.clicked.connect(self.on_click_light)
            self.calculateButton_compute.clicked.connect(self.on_click_compute)
            self.pushButton_create_beam.clicked.connect(self.on_click_create_light)
            self.pushButton_delete_beam.clicked.connect(self.on_click_delete_light)
            self.pushButton_save_beam.clicked.connect(self.save_light)
            self.pushButton_cancel_guide.clicked.connect(self.get_guide)
            self.pushButton_cancel_light.clicked.connect(self.get_light)
            self.pushButton_cancel_compute.clicked.connect(self.get_compute)
            self.pushButton_estimate_time.clicked.connect(self.show_estimate_time)
            self.pushButton_mode_number.clicked.connect(self.check_modes_display)

        def create_menu(self):
            """
            Create a menu to open, save a file, or exit the app.

            Notes
            -----
            This method connect the following methods and function to the
            menu buttons:

            :meth:`.open_file_name`, :meth:`.save_quick`, :meth:`.save_file_name`,
            :func:`.open_doc`.
            """
            folder = __file__  # Module name
            # Replaces characters only when called from outer files
            folder = folder.replace("\\", "/")
            folder = folder.split("/")
            folder = folder[:-1]  # Remove the file name
            folder2 = str()

            for line in folder:
                folder2 = folder2+"/"+line

            folder = folder2[1:]+"/"

            icon = QIcon()
            icon.addFile(folder+'icons/beampy-logo.png', QSize(256, 256))
            self.setWindowIcon(icon)

            menubar = self.menuBar()

            file = menubar.addMenu('File')

            action = file.addAction('Open')
            action.triggered.connect(self.open_file_name)
            action.setShortcut('Ctrl+O')
            icon = QIcon()
            icon.addFile(folder+'icons/document-open.png', QSize(22, 22))
            action.setIcon(icon)

            action = file.addAction('Save')
            action.triggered.connect(self.save_quick)
            action.setShortcut('Ctrl+S')
            icon = QIcon()
            icon.addFile(folder+'icons/document-save.png', QSize(22, 22))
            action.setIcon(icon)

            action = file.addAction('Save as')
            action.triggered.connect(self.save_file_name)
            action.setShortcut('Ctrl+Shift+S')
            icon = QIcon()
            icon.addFile(folder+'icons/document-save-as.png', QSize(22, 22))
            action.setIcon(icon)

            action = file.addAction('Exit')  # Clean exit for spyder
            action.setShortcut('Ctrl+Q')
            action.triggered.connect(QApplication.quit)
            icon = QIcon()
            icon.addFile(folder+'icons/application-exit.png', QSize(22, 22))
            action.setIcon(icon)

            file = menubar.addMenu('Help')

            action = file.addAction('Documentation')
            action.triggered.connect(open_doc)
            icon = QIcon()
            icon.addFile(folder+'icons/help-about.png', QSize(22, 22))
            action.setIcon(icon)

        def calculate_guide(self, topology='array'):
            """
            Initialized the :class:`.Bpm` class and creates the guides.

            Parameters
            ----------
            topology : str
                'array' or 'curved'.

            Notes
            -----
            Creats many variables, including :

            - peaks : Central position of each guide [guide,z].
            - dn : Difference of reefractive index [z,x].

            This method calls the following methods from :class:`.Bpm`:

            :meth:`.create_x_z`, :meth:`.squared_guide`, :meth:`.gauss_guide`,
            :meth:`.create_guides`, :meth:`.create_curved_guides`.
            """
            print("calculate guide")
            self.topology = topology
            t_guide_start = time.process_time()

            self.save_guide()  # Get all guide values

            # Create the Bpm class (overwrite existing one)
            self.bpm = Bpm(self.width, self.no, self.delta_no,
                           self.length_z, self.dist_z, self.nbr_z_disp,
                           self.length_x, self.dist_x)

            # windows variables
            [self.length_z, self.nbr_z, self.nbr_z_disp,
             self.length_x, self.nbr_x, self.x] = self.bpm.create_x_z()

            self.doubleSpinBox_length_x.setValue(self.length_x)
            self.doubleSpinBox_length_z.setValue(self.length_z)
            self.spinBox_nbr_z_disp.setValue(self.nbr_z_disp)

            if (self.nbr_x * self.nbr_z_disp) > (5000 * 1000):
                print("Error: if you want to have more points,")
                print("change the condition nbr_x * nbr_z_disp in calculate_guide")
                raise RuntimeError("Too many points:", self.nbr_x*self.nbr_z_disp)

            if (self.nbr_x * self.nbr_z) > (10000 * 15000) or (
                    self.nbr_z > 40000 or self.nbr_x > 40000):
                print("Error: if you want to have more points,")
                print("change the condition nbr_x * nbr_z in calculate_guide")
                raise RuntimeError("Too many points:", self.nbr_x*self.nbr_z)

            # Waveguide shape choice
            if self.shape_squared_check:
                shape = self.bpm.squared_guide()  # Squared guides
            elif self.shape_gauss_check:
                shape = self.bpm.gauss_guide(self.gauss_pow)  # Gaussian guides

            # Topology waveguides choice
            if topology == 'array':

                leng_max = self.length_x - self.dist_x

                if self.nbr_p*self.p > leng_max:
                    # give info about possible good values
                    print("nbr_p*p> length_x: ")
                    print(self.nbr_p*self.p, ">", leng_max)

                    print("p_max=", round(leng_max/self.nbr_p, 3))

                    if int(leng_max / self.p) == leng_max / self.p:
                        print("nbr_p_max=", int(leng_max / self.p)-1)
                    else:
                        print("nbr_p_max=", int(leng_max / self.p))

                    self.nbr_p = 0

                # choose guides position when even number
    #            condition_even_guide = 'center'  # default
    #            if self.nbr_p % 2 == 0:
    #                if condition_even_guide == 'left':
    #                    self.offset_guide -= self.p / 2
    #                elif condition_even_guide == 'right':
    #                    self.offset_guide += self.p / 2

                [self.peaks, self.dn] = self.bpm.create_guides(
                    shape, self.nbr_p, self.p, offset_guide=self.offset_guide)

            elif topology == 'curved':
                curve = self.curve * 1E-8  # curvature factor
                [self.peaks, self.dn] = self.bpm.create_curved_guides(
                    shape, curve, self.half_delay, self.distance_factor,
                    offset_guide=self.offset_guide)

            # Display guides
            self.z_disp = np.linspace(0,
                                      self.length_z / 1000,
                                      self.nbr_z_disp + 1)

            self.xv, self.zv = np.meshgrid(self.x, self.z_disp)
            self.dn_disp = np.linspace(0,
                                       self.nbr_z - 1,
                                       self.nbr_z_disp + 1, dtype=int)

            # only display available settings
            if self.nbr_p == 0 or self.p == 0:
                self.spinBox_offset_light_peak.setDisabled(True)
                self.doubleSpinBox_offset_light.setEnabled(True)
                self.checkBox_offset_light.setChecked(False)
                self.checkBox_offset_light.setDisabled(True)
                self.offset_check *= 0
                self.checkBox_lost.setDisabled(True)
                self.checkBox_lost.setChecked(False)
                self.frame_lost.setDisabled(True)
                self.checkBox_check_power.setDisabled(True)
            else:
                self.checkBox_offset_light.setEnabled(True)
                self.spinBox_offset_light_peak.setMaximum(self.peaks.shape[0]-1)
                self.checkBox_lost.setEnabled(True)
                self.spinBox_guide_lost.setMaximum(self.peaks.shape[0]-1)
                self.checkBox_check_power.setEnabled(True)

    #        Define new min/max for light and looses, based on selected guides
            self.doubleSpinBox_width_lost.setMaximum(self.length_x-self.dist_x)
            self.doubleSpinBox_lobe_size.setMaximum(self.length_x-self.dist_x)
            # If want to use min/max for offset: multiple beams will have issue if
            # the windows size change (min/max will only be for the displayed beam)
    #        self.doubleSpinBox_offset_light.setMinimum(self.x[0])
    #        self.doubleSpinBox_offset_light.setMaximum(self.x[-1])

            self.calculate_guide_done = True
            t_guide_end = time.process_time()
            print('Guides time: ', t_guide_end-t_guide_start)

        def calculate_light(self):
            """
            Create the choosen beams.

            Notes
            -----
            Creates the progress_pow variable.

            This method calls the following methods from the :class:`.Bpm` class:

            :meth:`.gauss_light`, :meth:`.squared_light`, :meth:`.all_modes`,
            :meth:`.mode_light`, :meth:`.airy_light`, :meth:`.init_field`.
            """
            print("calculate light")
            t_light_start = time.process_time()

            self.save_light()  # Get all light variables
            # must have same wavelength and angle or must compute for each
            # different wavelength or angle
            nbr_light = self.comboBox_light.count()  # Number of beams
            field = np.zeros((nbr_light, self.nbr_x))

            if sum(self.all_modes_check) > 0:  # Display only once the max mode
                self.check_modes_display()

            for i in range(nbr_light):

                # Check if offset relative to guide number or else in µm
                if self.offset_check[i] and self.peaks.shape[0] != 0:

                    # Reduce light # if > guides #
                    peaks_i = self.offset_light_peak[i]
                    peaks_max = self.spinBox_offset_light_peak.maximum()

                    if peaks_i > peaks_max:
                        print("beam", i+1, "has a non-existing guide position")
                        print("Change position from", peaks_i, "to", peaks_max)
                        self.offset_light_peak[i] = peaks_max

                    offset_light = self.peaks[self.offset_light_peak[i], 0]

                else:
                    offset_light = self.offset_light[i]

                #  Compute lights
                if self.gaussian_check[i]:
                    field_i = self.bpm.gauss_light(
                        self.fwhm[i], offset_light=offset_light)

                elif self.square_check[i]:
                    field_i = self.bpm.squared_light(
                        self.fwhm[i], offset_light=offset_light)

                elif self.all_modes_check[i]:
                    field_i = self.bpm.all_modes(
                        self.lo, offset_light=offset_light)[0]

                elif self.mode_check[i]:

                    try:
                        field_i = self.bpm.mode_light(
                            self.mode[i], self.lo, offset_light=offset_light)[0]

                    except ValueError as ex:  # Say that no mode exist
                        print(ex, "for the beam", i)
                        continue  # Go to the next field

                elif self.airy_check[i]:
                    [field_i, last_zero_pos] = self.bpm.airy_light(
                        self.lobe_size[i], self.airy_zero[i],
                        offset_light=offset_light)
                    self.spinBox_airy_zero.setValue(last_zero_pos)  # Corrected val

                field[i] = field_i

            irrad = self.irrad  # Irradiance or power (GW/cm^2)
            irrad = irrad * 1E13  # (W/m^2)
            [self.progress_pow] = self.bpm.init_field(
                field, self.theta_ext, irrad, self.lo)

            t_light_end = time.process_time()
            print('light time: ', t_light_end-t_light_start)

        def calculate_propagation(self):
            """
            Calculate the propagation based on the input light and guides shapes.

            Notes
            -----
            Creates the progress_pow variable.

            Calls the following methods from :class:`.Bpm`:
            :meth:`.losses_position`, meth`.main_compute`.
            """
            print("calculate propagation")
            t_compute_start = time.process_time()
            self.calculate_guide_done = False

            self.save_compute()

            kerr = self.kerr_check  # Active Kerr effect
            kerr_loop = self.kerr_loop
            chi3 = self.chi3 * 1E-20  # m^2/V^2
            variance_check = self.variance_check

            if self.lost_check:
                alpha = self.alpha/1000
                [lost_beg, lost_end] = self.bpm.losses_position(
                    self.guide_lost, self.width_lost)
            else:
                alpha = 0
                lost_beg = 0
                lost_end = 0

            estimation = round(
                8.8 / 5e7 * self.nbr_z * self.nbr_x  # without kerr
                * (1 + 0.72*self.kerr_check*(self.kerr_loop))  # with kerr
                + 3.8/5e6*self.nbr_z*self.nbr_x*self.variance_check  # control
                + 9/1e7*self.nbr_z*self.width_lost[0]/self.dist_x*self.lost_check,
                1)  # looses
            print("Time estimate:", estimation)

            [self.progress_pow] = self.bpm.main_compute(
                chi3=chi3, kerr=kerr, kerr_loop=kerr_loop,
                variance_check=variance_check, alpha=alpha,
                lost_beg=lost_beg, lost_end=lost_end)

            t_compute_end = time.process_time()
            print('Compute time: ', t_compute_end-t_compute_start)

        def show_estimate_time(self):
            """
            Display - on the interface - the estimate time needed to compute the
            propagation, based on linearized experimental values.
            The estimation takes into account the looses, Kerr, and control
            parameters.
            """
            self.save_compute()
            estimation = round(
                8.8 / 5e7 * self.nbr_z * self.nbr_x  # without kerr
                * (1 + 0.72*self.kerr_check*(self.kerr_loop))  # with kerr
                + 3.8/5e6*self.nbr_z*self.nbr_x*self.variance_check  # control
                + 9/1e7*self.nbr_z*self.width_lost[0]/self.dist_x*self.lost_check,
                1)  # looses

            self.estimate_time_display.display(estimation)

        def check_modes_display(self):
            """
            Display on the interface the last mode that can propagated into a
            squared guide.
            """
            lo = self.doubleSpinBox_lo.value()
            mode_max = self.bpm.check_modes(lo)
            self.mode_number.display(mode_max)

        def addmpl(self, tab='guide', pow_index=0):
            """
            Add the selected plots on the guide, light or compute window.

            Parameters
            ----------
            tab : str, optional
                'guide' or 'light'.
                'guide' by default.
            pow_index : int, optional
                Add the first guide and light step if 0 or the last step if -1.
                Also display the propagation into (x,z) and guide power if -1 is
                choosen.
                0 by default.
            """
            pow_index_guide = pow_index

            if pow_index < 0:
                pow_index_guide -= 1  # Display the -2 guide for the -1 beam

            x_min = self.x[0]
            x_max = self.x[-1]

            if (self.topology == 'array'  # If array of guides
                    and self.nbr_p != 0 and self.p != 0  # If guides exists
                    and self.peaks[0, 0] >= self.x[0]  # If guides in the windows
                    and self.peaks[-1, -1] <= self.x[-1]):
                x_min = self.offset_guide - self.nbr_p*self.p
                x_max = self.offset_guide + self.nbr_p*self.p

            if (self.topology == 'curved'  # If curved guides
                    and self.peaks[0, 0] >= self.x[0]  # If guides in the windows
                    and self.peaks[-1, -1] <= self.x[-1]):
                x_min = self.peaks[0, 0] - self.width
                x_max = self.peaks[-1, -1] + self.width

            if tab == 'guide':
                fig = Figure()
                fig.set_tight_layout(True)  # Prevent axes to be cut when resizing
                ax1 = fig.add_subplot(111)
                ax1.set_title("Guide shape through propagation")
                ax1.set_xlabel('x (µm)')
                ax1.set_ylabel('z (mm)')

                ax1.set_xlim(x_min, x_max)

                # note that a colormesh pixel is based on 4 points
                ax1.pcolormesh(self.xv,
                               self.zv,
                               self.dn[self.dn_disp],
                               cmap='gray')

                self.canvas_guide_prop = FigureCanvas(fig)
                self.plot_guide.addWidget(self.canvas_guide_prop)

                self.toolbar_guide_prop = NavigationToolbar(self.canvas_guide_prop,
                                                            self.canvas_guide_prop,
                                                            coordinates=True)
                self.plot_guide.addWidget(self.toolbar_guide_prop)

                fig = Figure()
                fig.set_tight_layout(True)
                ax2 = fig.add_subplot(111)
                ax2.set_title("Input index profil")
                ax2.set_xlabel('x (µm)')
                ax2.set_ylabel(r'$\Delta_n$')

                if self.nbr_p != 0:
                    verts = [(self.x[0], 0),
                             *zip(self.x, self.dn[pow_index_guide, :]),
                             (self.x[-1], 0)]
                    poly = Polygon(verts, facecolor='0.9', edgecolor='0.5')
                    ax2.add_patch(poly)

                ax2.set_xlim(x_min, x_max)

                if max(self.dn[0, :]) > max(self.dn[-1, :]):
                    ax2.set_ylim(0,
                                 max(self.dn[0, :])*1.1 + 1E-20)
                else:
                    ax2.set_ylim(0,
                                 max(self.dn[-1, :])*1.1 + 1E-20)

                ax2.plot(self.x, self.dn[pow_index_guide], 'k')

                self.canvas_guide_in = FigureCanvas(fig)
                self.plot_guide.addWidget(self.canvas_guide_in)

                self.toolbar_guide_in = NavigationToolbar(self.canvas_guide_in,
                                                          self.canvas_guide_in,
                                                          coordinates=True)
                self.plot_guide.addWidget(self.toolbar_guide_in)

            elif tab == 'light':
                fig = Figure()
                fig.set_tight_layout(True)
                ax1 = fig.add_subplot(111)
                ax1.set_title("Light injection into a guide")
                ax1.set_xlabel('x (µm)')
                ax2 = ax1.twinx()

                for tl in ax1.get_yticklabels():
                    tl.set_color('k')

                for tl in ax2.get_yticklabels():
                    tl.set_color('#1f77b4')

                ax1.set_ylabel(r'$\Delta_n$')
                ax2.set_ylabel('Irradiance ($GW.cm^{-2}$)')

                if self.nbr_p != 0:
                    verts = [(self.x[0], 0),
                             *zip(self.x, self.dn[pow_index_guide, :]),
                             (self.x[-1], 0)]
                    poly = Polygon(verts, facecolor='0.9', edgecolor='0.5')
                    ax1.add_patch(poly)

                ax1.set_xlim(x_min, x_max)

                ax1.set_ylim(0,
                             max(1.1*self.dn[pow_index_guide, :]) + 1E-20)

                if max(self.progress_pow[0]) != 0:
                    ax2.set_ylim(0, 1.1e-13*max(self.progress_pow[0]))

                ax1.plot(self.x, self.dn[pow_index_guide], 'k')
                ax2.plot(self.x, 1e-13*self.progress_pow[pow_index], '#1f77b4')

                # Display light at the beginning of guides
                if pow_index == 0:
                    self.canvas_light = FigureCanvas(fig)
                    self.plot_light.addWidget(self.canvas_light)

                    self.toolbar_2 = NavigationToolbar(self.canvas_light,
                                                       self.canvas_light,
                                                       coordinates=True)
                    self.plot_light.addWidget(self.toolbar_2)

                # Display light at the end of guides
                if pow_index < 0:
                    ax1.set_title("Light at the end of guides")
                    self.canvas_compute_end = FigureCanvas(fig)
                    self.plot_compute.addWidget(self.canvas_compute_end)

                    self.toolbar_4 = NavigationToolbar(self.canvas_compute_end,
                                                       self.canvas_compute_end,
                                                       coordinates=True)
                    self.plot_compute.addWidget(self.toolbar_4)

                    # Display light propagation into guides
                    fig = Figure()
                    fig.set_tight_layout(True)
                    ax1 = fig.add_subplot(111)
                    ax1.set_title("Light propagation into guides")
                    ax1.set_xlabel('x (µm)')
                    ax1.set_ylabel('z (mm)')

                    ax2.set_xlim(x_min, x_max)

                    ax1.pcolormesh(self.xv,
                                   self.zv,
                                   1e-13 * self.progress_pow)
                    self.canvas_compute_propag = FigureCanvas(fig)
                    self.plot_compute.addWidget(self.canvas_compute_propag)

                    self.toolbar_3 = NavigationToolbar(self.canvas_compute_propag,
                                                       self.canvas_compute_propag,
                                                       coordinates=True)
                    self.plot_compute.addWidget(self.toolbar_3)

                    # Display guides power
                    if (self.checkBox_check_power.isChecked() and
                            self.nbr_p != 0 and self.p != 0):
                        t_power_start = time.process_time()
                        fig = Figure()
    #                    fig.set_tight_layout(True)
                        ax1 = fig.add_subplot(111)
                        ax1.set_title("Radiant flux in guides")
                        ax1.set_ylim(0, 1)
                        ax1.set_xlabel('z (mm)')
                        ax1.set_ylabel('Radiant flux (u.a)')

                        x_beg = np.zeros((self.nbr_p, self.nbr_z), dtype=int)
                        x_end = np.zeros((self.nbr_p, self.nbr_z), dtype=int)
                        P = np.zeros((self.nbr_p, self.nbr_z_disp+1))
                        style = list(lines.lineStyles.keys())[0:-3]
                        style = style + list(lines.lineMarkers.keys())[0:-16]

                        if self.topology == 'array':
                            for n in range(self.nbr_p):
                                [x_beg[n, :],
                                 x_end[n, :]] = self.bpm.guide_position(n, self.p)

                        elif self.topology == 'curved':
                            # Choose precision at the end for right guide if can
                            # and choose safety when guides overlapse
                            if self.peaks[2, -1] <= self.x[-1]:
                                # When further of each other (good for right end)
                                p0 = self.peaks[2, -1] - self.peaks[1, -1]

                            else:
                                # When closest to each other (good when close)
                                p0 = self.width * self.distance_factor

                            for n in range(3):
                                [x_beg[n, :],
                                 x_end[n, :]] = self.bpm.guide_position(n, p0)

                        for n in range(self.peaks.shape[0]):
                            P[n, :] = self.bpm.power_guide(x_beg[n, :],
                                                           x_end[n, :])
                            # plot each power with a different style (nbr_p < 29)
                            if n < 29:
                                ax1.plot(self.z_disp, P[n, :],
                                         style[n], label='P'+str(n))

                            else:  # to have no error but same style
                                ax1.plot(self.z_disp, P[n, :],
                                         '', label='P'+str(n))

                        self.canvas_5 = FigureCanvas(fig)
                        self.verticalLayout_compute_plot.addWidget(self.canvas_5)

                        self.toolbar_5 = NavigationToolbar(self.canvas_5,
                                                           self.canvas_5,
                                                           coordinates=True)
                        self.verticalLayout_compute_plot.addWidget(self.toolbar_5)
                        if self.nbr_p > 10:
                            ax1.legend(loc="upper right")  # Fast if many plot
                        else:
                            ax1.legend()  # Best if not too many plot
                        ax1.grid()
                        t_power_end = time.process_time()
                        print('Power time: ', t_power_end-t_power_start)

        def rmmpl(self, tab, pow_index=0):
            """
            Remove the selected plots

            Parameters
            ----------
            tab : str
                'guide' or 'light'.
            pow_index : int, optional
                Remove the first light step if 0 or the last step if -1.
                0 by default.
            """
            if tab == 'guide':
                self.plot_guide.removeWidget(self.canvas_guide_prop)
                self.plot_guide.removeWidget(self.canvas_guide_in)
                self.canvas_guide_prop.close()
                self.canvas_guide_in.close()

                self.plot_guide.removeWidget(self.toolbar_guide_prop)
                self.plot_guide.removeWidget(self.toolbar_guide_in)
                self.toolbar_guide_prop.close()
                self.toolbar_guide_in.close()

            elif tab == 'light':
                if pow_index == 0:
                    self.plot_light.removeWidget(self.canvas_light)
                    self.canvas_light.close()
                    self.plot_light.removeWidget(self.toolbar_2)
                    self.toolbar_2.close()

                if pow_index < 0:
                    self.plot_compute.removeWidget(self.canvas_compute_propag)
                    self.canvas_compute_propag.close()
                    self.plot_compute.removeWidget(self.toolbar_3)
                    self.toolbar_3.close()

                    self.verticalLayout_compute_plot.removeWidget(self.canvas_5)
                    self.canvas_5.close()
                    self.verticalLayout_compute_plot.removeWidget(self.toolbar_5)
                    self.toolbar_5.close()

                    self.plot_compute.removeWidget(self.canvas_compute_end)
                    self.canvas_compute_end.close()
                    self.plot_compute.removeWidget(self.toolbar_4)
                    self.toolbar_4.close()

        def save_guide(self):
            """
            Save the interface variables into the guides variables.
            """
            self.length_z = self.doubleSpinBox_length_z.value()
            self.dist_z = self.doubleSpinBox_dist_z.value()
            self.nbr_z_disp = self.spinBox_nbr_z_disp.value()
            self.length_x = self.doubleSpinBox_length_x.value()
            self.dist_x = self.doubleSpinBox_dist_x.value()

            self.width = self.doubleSpinBox_width.value()
            self.offset_guide = self.doubleSpinBox_offset_guide.value()
            self.no = self.doubleSpinBox_n.value()
            self.delta_no = self.doubleSpinBox_dn.value()

            self.shape_gauss_check = float(self.radioButton_gaussian.isChecked())
            self.gauss_pow = int(self.spinBox_gauss_pow.value())
            self.shape_squared_check = float(self.radioButton_squared.isChecked())

            self.nbr_p = self.spinBox_nb_p.value()
            self.p = self.doubleSpinBox_p.value()

            self.curve = self.doubleSpinBox_curve.value()
            self.half_delay = self.doubleSpinBox_half_delay.value()
            self.distance_factor = self.doubleSpinBox_distance_factor.value()

            self.tab_index = self.tabWidget_morphology_guide.currentIndex()
    #        print("Guide variables saved")

        def get_guide(self):
            """
            Set the saved values of the guide variables on the interface.
            """
            self.doubleSpinBox_length_z.setValue(self.length_z)
            self.doubleSpinBox_dist_z.setValue(self.dist_z)
            self.spinBox_nbr_z_disp.setValue(self.nbr_z_disp)
            self.doubleSpinBox_length_x.setValue(self.length_x)
            self.doubleSpinBox_dist_x.setValue(self.dist_x)

            self.doubleSpinBox_width.setValue(self.width)
            self.doubleSpinBox_offset_guide.setValue(self.offset_guide)
            self.doubleSpinBox_n.setValue(self.no)
            self.doubleSpinBox_dn.setValue(self.delta_no)

            self.radioButton_gaussian.setChecked(self.shape_gauss_check)
            self.spinBox_gauss_pow.setValue(self.gauss_pow)
            self.radioButton_squared.setChecked(self.shape_squared_check)

            self.spinBox_nb_p.setValue(self.nbr_p)
            self.doubleSpinBox_p.setValue(self.p)

            self.doubleSpinBox_curve.setValue(self.curve)
            self.doubleSpinBox_half_delay.setValue(self.half_delay)
            self.doubleSpinBox_distance_factor.setValue(self.distance_factor)

            self.tabWidget_morphology_guide.setCurrentIndex(self.tab_index)

        def save_light(self, beam_selec=False):
            """
            Save the interface variables into the lights variables.

            Parameters
            ----------
            beam_selec: int, bool, optional
                Number of the beam to save into the variables.
                False by default to get the currently displayed beam.
            """
            self.lo = self.doubleSpinBox_lo.value()
            self.theta_ext = self.doubleSpinBox_theta_ext.value()

            # if more than one beams and if no beams selected manualy
            if str(beam_selec) == 'False':
                beam_selec = int(self.comboBox_light.currentIndex())  # Choice

            self.fwhm[beam_selec] = self.doubleSpinBox_fwhm.value()
            self.offset_light[beam_selec] = self.doubleSpinBox_offset_light.value()
            self.irrad[beam_selec] = self.doubleSpinBox_intensity_light.value()
            self.mode[beam_selec] = self.spinBox_mode.value()
            self.offset_check[beam_selec] = (
                self.checkBox_offset_light.isChecked())
            self.offset_light_peak[beam_selec] = (
                self.spinBox_offset_light_peak.value())
            self.gaussian_check[beam_selec] = (
                self.radioButton_gaussian_light.isChecked())
            self.square_check[beam_selec] = (
                self.radioButton_squared_light.isChecked())
            self.mode_check[beam_selec] = self.radioButton_mode.isChecked()
            self.all_modes_check[beam_selec] = (
                self.radioButton_all_modes.isChecked())
            self.airy_check[beam_selec] = (
                self.radioButton_airy.isChecked())
            self.airy_zero[beam_selec] = self.spinBox_airy_zero.value()
            self.lobe_size[beam_selec] = self.doubleSpinBox_lobe_size.value()

        def get_light(self):
            """
            Set the saved values of the light variables on the interface.
            """
            beam_selec = int(self.comboBox_light.currentIndex())  # choice

            if self.previous_beam != beam_selec:
                self.save_light(self.previous_beam)

            self.doubleSpinBox_lo.setValue(self.lo)
            self.doubleSpinBox_theta_ext.setValue(self.theta_ext)

            if self.comboBox_light.count() >= 1:  # if more than one beams
                beam_selec = int(self.comboBox_light.currentIndex())  # choice
            else:  # Not supposed to happen
                raise ValueError("Can't have no beam variables")

            self.doubleSpinBox_fwhm.setValue(self.fwhm[beam_selec])
            self.doubleSpinBox_offset_light.setValue(
                self.offset_light[beam_selec])
            self.doubleSpinBox_intensity_light.setValue(self.irrad[beam_selec])
            self.spinBox_mode.setValue(self.mode[beam_selec])
            self.checkBox_offset_light.setChecked(self.offset_check[beam_selec])
            self.spinBox_offset_light_peak.setValue(
                self.offset_light_peak[beam_selec])
            self.radioButton_gaussian_light.setChecked(
                self.gaussian_check[beam_selec])
            self.radioButton_squared_light.setChecked(
                self.square_check[beam_selec])
            self.radioButton_mode.setChecked(self.mode_check[beam_selec])
            self.radioButton_all_modes.setChecked(
                self.all_modes_check[beam_selec])
            # if checkBox_offset_light checked then activate
            self.spinBox_offset_light_peak.setEnabled(
                self.offset_check[beam_selec])
            self.doubleSpinBox_offset_light.setDisabled(
                self.offset_check[beam_selec])
            self.radioButton_airy.setChecked(self.airy_check[beam_selec])
            self.spinBox_airy_zero.setValue(self.airy_zero[beam_selec])
            self.doubleSpinBox_lobe_size.setValue(self.lobe_size[beam_selec])

            self.previous_beam = beam_selec  # Save the number of the current beam

        def save_compute(self):
            """
            Save the interface variables into the compute variables.
            """
            self.lost_check = float(self.checkBox_lost.isChecked())
            self.guide_lost = np.array(
                [self.spinBox_guide_lost.value()], dtype=int)
            self.width_lost = np.array([self.doubleSpinBox_width_lost.value()])
            self.alpha = self.doubleSpinBox_lost.value()

            self.kerr_check = float(self.checkBox_kerr.isChecked())
            self.kerr_loop = self.spinBox_kerr_loop.value()
            self.chi3 = self.doubleSpinBox_chi3.value()
            self.variance_check = float(self.checkBox_variance.isChecked())
            self.power_check = float(self.checkBox_check_power.isChecked())
    #        print("Compute variables saved")

        def get_compute(self):
            """
            Set the saved values of the compute variables on the interface.
            """
            self.checkBox_lost.setChecked(self.lost_check)
            self.frame_lost.setEnabled(self.lost_check)
            self.spinBox_guide_lost.setValue(self.guide_lost[0])
            self.doubleSpinBox_width_lost.setValue(self.width_lost[0])
            self.doubleSpinBox_lost.setValue(self.alpha)

            self.checkBox_kerr.setChecked(self.kerr_check)
            self.spinBox_kerr_loop.setValue(self.kerr_loop)
            self.doubleSpinBox_chi3.setValue(self.chi3)
            self.frame_kerr.setEnabled(self.kerr_check)
            self.checkBox_variance.setEnabled(self.kerr_check)
            self.checkBox_variance.setChecked(self.variance_check)
            if not self.kerr_check:
                self.checkBox_variance.setChecked(False)
            self.checkBox_check_power.setChecked(self.power_check)

        @pyqtSlot()
        def on_click_array(self):
            """
            Compute and displayed a guide array.
            """
    #        print('button click guide array')
            QApplication.setOverrideCursor(Qt.WaitCursor)
            self.rmmpl('guide')
            self.rmmpl('light')
            self.calculate_guide('array')
            self.calculate_light()
            self.addmpl('guide')
            self.addmpl('light')
            QApplication.restoreOverrideCursor()
            self.show_estimate_time()

        @pyqtSlot()
        def on_click_curved(self):
            """
            Compute and displayed curved guides.
            """
    #        print('button click guide curved')
            QApplication.setOverrideCursor(Qt.WaitCursor)
            self.rmmpl('guide')
            self.rmmpl('light')
            self.calculate_guide('curved')
            self.calculate_light()
            self.addmpl('guide')
            self.addmpl('light')
            QApplication.restoreOverrideCursor()
            self.show_estimate_time()

        @pyqtSlot()
        def on_click_light(self):
            """
            Compute the light and display it with guides.
            """
    #        print('button click light')
            QApplication.setOverrideCursor(Qt.WaitCursor)
            self.rmmpl(tab='light')
            self.calculate_light()
            self.addmpl(tab='light')
            QApplication.restoreOverrideCursor()
            self.show_estimate_time()

        @pyqtSlot()
        def on_click_compute(self):
            """
            Compute the propagation using the guide and light informations.
            """
    #        print('button click compute')
            QApplication.setOverrideCursor(Qt.WaitCursor)
            self.show_estimate_time()

            if max(self.progress_pow[0]) != 0:

                self.rmmpl(tab='light', pow_index=-1)

                if not self.calculate_guide_done:
                    self.rmmpl('guide')
                    self.calculate_guide(self.topology)
                    self.addmpl('guide')
                    self.rmmpl(tab='light')
                    self.calculate_light()
                    self.addmpl(tab='light')

                self.calculate_propagation()
                self.addmpl(tab='light', pow_index=-1)

            else:
                print("no light to compute")

            QApplication.restoreOverrideCursor()

        @pyqtSlot()
        def on_click_create_light(self):
            """Create a new beam with the displayed variables.
            """
            fwhm = self.doubleSpinBox_fwhm.value()
            offset_light = self.doubleSpinBox_offset_light.value()
            irrad = self.doubleSpinBox_intensity_light.value()
            offset_check = self.checkBox_offset_light.isChecked()
            gaussian_check = self.radioButton_gaussian_light.isChecked()
            square_check = self.radioButton_squared_light.isChecked()
            mode_check = self.radioButton_mode.isChecked()
            all_modes_check = self.radioButton_all_modes.isChecked()
            mode = self.spinBox_mode.value()
            offset_light_peak = self.spinBox_offset_light_peak.value()
            airy_check = self.radioButton_airy.isChecked()
            airy_zero = self.spinBox_airy_zero.value()
            lobe_size = self.doubleSpinBox_lobe_size.value()

            self.fwhm = np.append(self.fwhm, fwhm)
            self.offset_light = np.append(self.offset_light, offset_light)
            self.irrad = np.append(self.irrad, irrad)
            self.mode = np.append(self.mode, mode)
            self.offset_check = np.append(self.offset_check, offset_check)
            self.offset_light_peak = np.append(self.offset_light_peak,
                                               offset_light_peak)
            self.gaussian_check = np.append(self.gaussian_check, gaussian_check)
            self.square_check = np.append(self.square_check, square_check)
            self.mode_check = np.append(self.mode_check, mode_check)
            self.all_modes_check = np.append(self.all_modes_check, all_modes_check)
            self.airy_check = np.append(self.airy_check, airy_check)
            self.airy_zero = np.append(self.airy_zero, airy_zero)
            self.lobe_size = np.append(self.lobe_size, lobe_size)

            nbr_light = self.comboBox_light.count()  # how many item left
            self.comboBox_light.addItem("Beam "+str(nbr_light+1))  # add new index
            self.comboBox_light.setCurrentIndex(nbr_light)  # show new index
            self.previous_beam = nbr_light  # Change the current selected beam

        @pyqtSlot()
        def on_click_delete_light(self):
            """
            Delete the current displayed beam and displayed the next one.
            """
            nbr_light = self.comboBox_light.count()

            if nbr_light > 1:  # Can't delete if remains only 1 beam
                beam_selec = int(self.comboBox_light.currentIndex())  # choice
                self.fwhm = np.delete(self.fwhm, beam_selec)
                self.offset_light = np.delete(self.offset_light, beam_selec)
                self.irrad = np.delete(self.irrad, beam_selec)
                self.mode = np.delete(self.mode, beam_selec)
                self.offset_check = np.delete(self.offset_check, beam_selec)
                self.offset_light_peak = np.delete(self.offset_light_peak,
                                                   beam_selec)
                self.gaussian_check = np.delete(self.gaussian_check, beam_selec)
                self.square_check = np.delete(self.square_check, beam_selec)
                self.mode_check = np.delete(self.mode_check, beam_selec)
                self.all_modes_check = np.delete(self.all_modes_check,
                                                 beam_selec)
                self.airy_check = np.delete(self.airy_check, beam_selec)
                self.airy_zero = np.delete(self.airy_zero, beam_selec)
                self.lobe_size = np.delete(self.lobe_size, beam_selec)

                nbr_light -= 1

                self.comboBox_light.clear()  # remove all beams number

                for i in range(nbr_light):  # create again with new number
                    self.comboBox_light.addItem("Beam "+str(i+1))

                # set same beam index if not the last else reduce the index by 1
                if beam_selec == nbr_light and beam_selec != 0:
                    beam_selec -= 1

                self.comboBox_light.setCurrentIndex(beam_selec)
                self.previous_beam = beam_selec  # Change the current selected beam
                self.get_light()  # Display values of the previous or next beam

        @pyqtSlot()
        def open_file_name(self):
            """
            Open a dialog window to select the file to open, and call
            :meth:`open_file` to open the file.

            Source: https://pythonspot.com/pyqt5-file-dialog/

            Notes
            -----
            This method has a try/except implemented to check if the openned file
            contains all the variables.
            """

            options = QFileDialog.Options()
            options |= QFileDialog.DontUseNativeDialog
            filename, _ = QFileDialog.getOpenFileName(self,
                                                      "Import data",
                                                      "",
                                                      "Text Files (*.txt)",
                                                      options=options)
            if filename:
                try:
                    self.open_file(filename)
                    self.filename = filename  # Next save will overwrite this file
                    self.setWindowTitle("Beampy - "+filename)
                except KeyError as ex:
                    print("missing variable", ex, "in the file.")
                    print("Add it manually to remove this error.")
    #            except Exception as ex:  # This execption was removed to see the
                    # # error location. The program won't crash thanks to try
    #                print("Unknown error when openning the file:", filename)
    #                print("Error:", ex)

        def open_file(self, filename):
            """
            Set guides, beams and computes variables from a choosen file.

            Parameters
            ----------
            filename : str
                Name of the file.
            """
    #        https://www.tutorialspoint.com/
    #        How-to-create-a-Python-dictionary-from-text-file
            dico = {}
            f = open(filename, 'r')
            for line in f:
                (variables, *val) = line.split()  # Assume: variable_name values
    #            print(variables, val)
                dico[str(variables)] = val
            f.close()

            # Save the displayed values (only useful if the displayed variable is
    #       not in the openned file)
            self.save_guide()
            self.save_light()
            self.save_compute()

            # Guide variables
    #        if dico.get('length_z') is not None: # if want to continue without the
    #        variable and choose the displayed values instead
            self.length_z = float(dico['length_z'][0])
            self.dist_z = float(dico['dist_z'][0])
            self.nbr_z_disp = int(dico['nbr_z_disp'][0])
            self.length_x = float(dico['length_x'][0])
            self.dist_x = float(dico['dist_x'][0])

            self.width = float(dico['width'][0])
            self.offset_guide = float(dico['offset_guide'][0])
            self.no = float(dico['no'][0])
            self.delta_no = float(dico['delta_no'][0])

            self.shape_gauss_check = float(dico['shape_gauss_check'][0])
            self.gauss_pow = int(dico['gauss_pow'][0])
            self.shape_squared_check = float(dico['shape_squared_check'][0])

            self.nbr_p = int(dico['nbr_p'][0])
            self.p = float(dico['p'][0])

            self.curve = float(dico['curve'][0])
            self.half_delay = float(dico['half_delay'][0])
            self.distance_factor = float(dico['distance_factor'][0])

            self.tab_index = int(dico['tab_index'][0])

            # Light variables
            self.lo = float(dico['lo'][0])
            self.theta_ext = float(dico['theta_ext'][0])

            self.fwhm = np.array(dico['fwhm'], dtype=float)
            self.offset_light = np.array(dico['offset_light'], dtype=float)
            self.irrad = np.array(dico['irrad'], dtype=float)
            self.offset_check = np.array(dico['offset_check'], dtype=float)
            self.gaussian_check = np.array(dico['gaussian_check'], dtype=float)
            self.square_check = np.array(dico['square_check'], dtype=float)
            self.mode_check = np.array(dico['mode_check'], dtype=float)
            self.all_modes_check = np.array(dico['all_modes_check'], dtype=float)
            self.mode = np.array(dico['mode'], dtype=int)
            self.offset_light_peak = np.array(
                dico['offset_light_peak'], dtype=int)
            self.airy_check = np.array(dico['airy_check'], dtype=float)
            self.airy_zero = np.array(dico['airy_zero'], dtype=int)
            self.lobe_size = np.array(dico['lobe_size'], dtype=float)

            # Compute variables
            self.lost_check = float(dico['lost_check'][0])
            self.guide_lost = np.array(dico['guide_lost'], dtype=int)
            self.width_lost = np.array(dico['width_lost'], dtype=float)
            self.alpha = float(dico['alpha'][0])
            self.kerr_check = float(dico['kerr_check'][0])
            self.kerr_loop = int(dico['kerr_loop'][0])
            self.chi3 = float(dico['chi3'][0])
            self.variance_check = float(dico['variance_check'][0])
            self.power_check = float(dico['power_check'][0])

            nbr_light = len(self.fwhm)
            self.comboBox_light.clear()  # Remove all beams number

            for i in range(nbr_light):  # Create again with new number
                self.comboBox_light.addItem("Beam "+str(i+1))

            self.previous_beam = 0  # Change the current selected beam

            if self.tab_index == 0 and self.nbr_p != 0:  # Array of guides
                self.spinBox_offset_light_peak.setMaximum(self.nbr_p-1)
                self.spinBox_guide_lost.setMaximum(self.nbr_p-1)
            elif self.tab_index == 1:  # Curved guides
                self.spinBox_offset_light_peak.setMaximum(3-1)
                self.spinBox_guide_lost.setMaximum(3-1)

            self.get_guide()  # Set guides boxes value
            self.get_light()  # Set lights boxes value
            self.get_compute()  # Set compute boxes value

            if self.tab_index == 0:  # If openned file uses array
                self.on_click_array()
            elif self.tab_index == 1:  # If openned file uses curved guides
                self.on_click_curved()
            print("file openned")

        @pyqtSlot()
        def save_quick(self):
            """
            Check if a file is already selected and if so, save into it.
            Else, call the :meth:`save_file_name` to ask a filename.
            """
            if self.filename is None:
                self.save_file_name()
            else:
                self.save_file(self.filename)

        def save_file_name(self):
            """
            Open a dialog window to select the saved file name and call
            :meth:`save_file` to save the file.
            """
            options = QFileDialog.Options()
            options |= QFileDialog.DontUseNativeDialog
            filename, _ = QFileDialog.getSaveFileName(self,
                                                      "Save data",
                                                      "",
                                                      "Text Files (*.txt)",
                                                      options=options)
            if filename:
                if filename[-4:] != '.txt':
                    filename = filename + '.txt'
                self.filename = filename
                self.save_file(filename)
                self.setWindowTitle("Beampy - "+filename)

        def save_file(self, filename):
            """
            Save guides, beams and computes variables into a choosen file.

            Parameters
            ----------
            filename : str
                Name of the file.
            """
            self.save_guide()
            self.save_light()
            self.save_compute()

            f = open(filename, "w")

            # Guide variables
            f.write('length_z ' + str(self.length_z) + '\n')
            f.write('dist_z ' + str(self.dist_z) + '\n')
            f.write('nbr_z_disp ' + str(self.nbr_z_disp) + '\n')
            f.write('length_x ' + str(self.length_x) + '\n')
            f.write('dist_x ' + str(self.dist_x) + '\n')

            f.write('width ' + str(self.width) + '\n')
            f.write('offset_guide ' + str(self.offset_guide) + '\n')
            f.write('no ' + str(self.no) + '\n')
            f.write('delta_no ' + str(self.delta_no) + '\n')

            f.write('shape_gauss_check ' + str(self.shape_gauss_check) + '\n')
            f.write('gauss_pow ' + str(self.gauss_pow) + '\n')
            f.write('shape_squared_check ' + str(self.shape_squared_check) + '\n')

            f.write('nbr_p ' + str(self.nbr_p) + '\n')
            f.write('p ' + str(self.p) + '\n')

            f.write('curve ' + str(self.curve) + '\n')
            f.write('half_delay ' + str(self.half_delay) + '\n')
            f.write('distance_factor ' + str(self.distance_factor) + '\n')
            f.write('tab_index ' + str(self.tab_index) + '\n')

            # light variables
            f.write('lo ' + str(self.lo) + '\n')
            f.write('theta_ext ' + str(self.theta_ext) + '\n')

            f.write('fwhm '
                    + str(self.fwhm).replace("[", "").replace("]", "")
                    + '\n')
            f.write('offset_light '
                    + str(self.offset_light).replace("[", "").replace("]", "")
                    + '\n')
            f.write('irrad '
                    + str(self.irrad).replace("[", "").replace("]", "")
                    + '\n')
            f.write('offset_check '
                    + str(self.offset_check).replace("[", "").replace("]", "")
                    + '\n')
            f.write('gaussian_check '
                    + str(self.gaussian_check).replace("[", "").replace("]", "")
                    + '\n')
            f.write('square_check '
                    + str(self.square_check).replace("[", "").replace("]", "")
                    + '\n')
            f.write('mode_check '
                    + str(self.mode_check).replace("[", "").replace("]", "")
                    + '\n')
            f.write('all_modes_check '
                    + str(self.all_modes_check).replace("[", "").replace("]", "")
                    + '\n')
            f.write('mode '
                    + str(self.mode).replace("[", "").replace("]", "")
                    + '\n')
            f.write('offset_light_peak '
                    + str(self.offset_light_peak).replace("[", "").replace("]", "")
                    + '\n')
            f.write('airy_check '
                    + str(self.airy_check).replace("[", "").replace("]", "")
                    + '\n')
            f.write('airy_zero '
                    + str(self.airy_zero).replace("[", "").replace("]", "")
                    + '\n')
            f.write('lobe_size '
                    + str(self.lobe_size).replace("[", "").replace("]", "")
                    + '\n')

            # compute variables
            f.write('lost_check ' + str(self.lost_check) + '\n')
            f.write('guide_lost '
                    + str(self.guide_lost).replace("[", "").replace("]", "")
                    + '\n')
            f.write('width_lost '
                    + str(self.width_lost).replace("[", "").replace("]", "")
                    + '\n')
            f.write('alpha ' + str(self.alpha) + '\n')
            f.write('kerr_check ' + str(self.kerr_check) + '\n')
            f.write('kerr_loop ' + str(self.kerr_loop) + '\n')
            f.write('chi3 ' + str(self.chi3) + '\n')
            f.write('variance_check ' + str(self.variance_check) + '\n')
            f.write('power_check ' + str(self.power_check) + '\n')
            f.close()
            print("file saved")

    def open_doc():
        """
        Function that open the local html documentation - describing the beampy
        modules - if exist, or the online version otherwise.
        """
        file = __file__  # Module name
        # Replaces characters only when called from outer files
        file = file.replace("\\", "/")
        file = file.split("/")
        file = file[:-2]  # Remove the folder and file name

        file2 = str()
        for line in file:
            file2 = file2+"/"+line

        file = file2[1:]+"/docs/html/index.html"
        exists = os.path.isfile(file)

        if exists:
            webbrowser.open(file, new=2)  # Open file in a new tab (new=2)
        else:
            print("The documentation can't be found localy in:", file)
            file = "https://beampy.readthedocs.io"
            print("Openning the online version at:", file)
            webbrowser.open(file, new=2)  # Open file in a new tab (new=2)

    def open_app():
        """
        Function used to open the app.
        Can be called directly from beampy.
        """
        app = QApplication(sys.argv)  # Define the app
        myapp = UserInterface()  # Run the app
        myapp.show()  # Show the form
        app.exec_()  # Execute the app in a loop

    if __name__ == "__main__":
        open_app()

## beampy.examples

    from beampy.bpm import Bpm
    import matplotlib.pyplot as plt
    import numpy as np
    from numpy.fft import fft, ifft, fftshift
    from math import pi, ceil, radians, sqrt, log, sin, cos, acos, asin, exp

    def example_gaussian_beam():
        """ Display a Gaussian beam with the fwhm definition."""
        fwhm = 6
        bpm = Bpm(1, 1, 1, 1, 1, 1, 1, 1)
        bpm.x = np.linspace(-15, 9.1, 500)
        x = bpm.x
        plt.figure("Beam")
        plt.title("Example for the gaussian beam")
        plt.plot(x, bpm.gauss_light(fwhm, 0), label='field')
        plt.plot(x, (bpm.gauss_light(fwhm, 0))**2, label='intensity')
        plt.plot(x, [1/2]*x.size, '-.', label='1/2')
        plt.plot([fwhm/2]*x.size, np.linspace(0, 1, x.size), '--', label='fwhm/2')
        plt.plot(x, [np.exp(-1)]*x.size, '-.', label='1/e')
        plt.plot(x, [np.exp(-2)]*x.size, '-.', label='1/$e^2$')
        plt.plot([fwhm / np.sqrt(2 * np.log(2))]*x.size, np.linspace(0, 1, x.size),
                 '--', label='$w_0$')
        plt.legend()
        plt.show()

    def example_guides_x():
        """Display a Gaussian guide, two super-Gaussian guides and a flat-top guide
        to illustrate the width definition."""
        width = 6
        bpm = Bpm(width, 1, 1, 1, 1, 1, 1, 1)
        bpm.x = np.linspace(-15, 9.1, 500)
        x = bpm.x
        plt.figure("guide_x")
        plt.title("Example of different guides")
        plt.plot(x, bpm.gauss_guide(1)(x), label='Gaussian')
        plt.plot(x, bpm.gauss_guide(4)(x), label='super-Gaussian P=4')
        plt.plot(x, bpm.gauss_guide(10)(x), label='super-Gaussian P=10')
        plt.plot(x, bpm.squared_guide()(x), label='Flat-top')
        plt.plot([width/2]*x.size, np.linspace(0, 1, x.size), '--',
                 label='width/2')
        plt.plot(x, [np.exp(-1)]*x.size, '-.', label='1/e')
        plt.legend()
        plt.show()

    def example_guides_z():
        """Display an array of guides and the curved guides system."""
        width = 6
        bpm = Bpm(width, 2, 0.1, 10000, 1, 200, 100, 0.1)
        [length_z, nbr_z, nbr_z_disp, length_x, nbr_x, x] = bpm.create_x_z()
        shape = bpm.gauss_guide(4)
        [peaks, dn] = bpm.create_guides(shape, 5, 10)
        z_disp = np.linspace(0, length_z/1000, nbr_z_disp+1)
        xv, zv = np.meshgrid(x, z_disp)
        dn_disp = np.linspace(0, nbr_z-1, nbr_z_disp+1, dtype=int)
        plt.figure("guide_z_array")
        plt.title("Example for the array of guides")
        plt.pcolormesh(xv, zv, dn[dn_disp], cmap='gray')
        plt.show()
        [peaks, dn] = bpm.create_curved_guides(shape, 40*1e-8, 1000, 1.2)
        plt.figure("guide_z_curved")
        plt.title("Example for the curved guides")
        plt.pcolormesh(xv, zv, dn[dn_disp], cmap='gray')
        plt.show()

    def example_free_propag():
        """Show the free propagation of a beam (no refractive index variation)
        and confirm that Beampy return the correct waist value"""
        width = 0
        no = 1
        delta_no = 0
        length_z = 10000
        dist_z = 10000
        nbr_z_disp = 1
        dist_x = 0.01
        length_x = 1000

        bpm = Bpm(width, no, delta_no,
                  length_z, dist_z, nbr_z_disp,
                  length_x, dist_x)

        [length_z, nbr_z, nbr_z_disp, length_x, nbr_x, x] = bpm.create_x_z()

        shape = bpm.squared_guide()

        nbr_p = 0
        p = 0

        [peaks, dn] = bpm.create_guides(shape, nbr_p, p)

        fwhm = 20
        lo = 1.5

        field = bpm.gauss_light(fwhm)
        irrad = 1E13
        theta_ext = 0

        [progress_pow] = bpm.init_field(field, theta_ext, irrad, lo)

        [progress_pow] = bpm.main_compute()

        intensity = progress_pow[-1]

        fwhm2 = np.where(
                intensity >= (max(intensity)/2)
        )[0][0]

        fwhm_final = abs(2 * x[fwhm2])

        w0_final = fwhm_final / np.sqrt(2 * np.log(2))
        print("Beampy:", w0_final)

        w0 = fwhm / np.sqrt(2 * np.log(2))
        z0 = np.pi * w0**2 / lo
        w = w0 * np.sqrt(1 + (length_z / z0)**2)

        print("Theory:", w)
        print("relative difference:", abs(w - w0_final)/w*100, "%")

    def example_stability():
        """Show the possible BPM approximations for implementing a refractive
        index variation"""

        width = 6
        no = 2.14
        delta_no = 0.0014
        length_z = 200
        dist_z = 10
        nbr_z_disp = 1
        dist_x = 0.1
        length_x = 1000

        bpm = Bpm(width, no, delta_no,
                  length_z, dist_z, nbr_z_disp,
                  length_x, dist_x)

        [length_z, nbr_z, nbr_z_disp, length_x, nbr_x, x] = bpm.create_x_z()

        shape = bpm.squared_guide()

        nbr_p = 1
        p = 0

        [peaks, dn] = bpm.create_guides(shape, nbr_p, p)

        fwhm = 6
        lo = 1.5

        field = bpm.gauss_light(fwhm)
        irrad = 1
        theta_ext = 0

        [progress_pow] = bpm.init_field(field, theta_ext, irrad, lo)

        nbr_step = 10

        # Need to overwrite those variables due to changes
        theta = asin(sin(radians(theta_ext)) / no)  # angle in the guide
        nu_max = 1 / (2 * dist_x)  # max frequency due to sampling
        # Spacial frequencies over x (1/µm)
        nu = np.linspace(-nu_max,
                         nu_max * (1 - 2/nbr_x),
                         nbr_x)
        intermed = no * cos(theta) / lo
        fr = -2 * pi * nu**2 / (intermed + np.sqrt(
            intermed**2
            - nu**2
            + 0j))

        bpm.phase_mat = fftshift(np.exp(1j * dist_z * fr))
        bpm.phase_mat_demi = fftshift(np.exp(1j * dist_z / 2 * fr))
        # End overwrite

        field = bpm.field
        for i in range(nbr_step):
            field = ifft(bpm.phase_mat * fft(field))
            field *= np.exp(1j * bpm.nl_mat[nbr_step, :])
        test_1 = field

        field = bpm.field
        for i in range(nbr_step):
            field = ifft(bpm.phase_mat_demi * fft(field))
            field *= np.exp(1j * bpm.nl_mat[nbr_step, :])
            field = ifft(bpm.phase_mat_demi * fft(field))
        test_2 = field

        field = bpm.field
        for i in range(nbr_step):
            field *= np.exp(1j * bpm.nl_mat[nbr_step, :])
            field = ifft(bpm.phase_mat * fft(field))
        test_3 = field

        plt.figure("field real")
        plt.title("Impact of the free propagation order")
        plt.xlim(-20, 20)
        plt.ylim(-1, 20)
        plt.plot(x, test_1.real, label='first: dz+lens')
        plt.plot(x, test_2.real, label='middle: dz/2+lens+dz/2')
        plt.plot(x, test_3.real, label='last: lens+dz')
        plt.legend()
        plt.show()
        plt.figure("field imag")
        plt.title("Impact of the free propagation order")
        plt.xlim(-30, 30)
        plt.plot(x, test_1.imag, label='first: dz+lens')
        plt.plot(x, test_2.imag, label='middle: dz/2+lens+dz/2')
        plt.plot(x, test_3.imag, label='last: lens+dz')
        plt.legend()
        plt.show()

        field = bpm.field
        field = ifft(bpm.phase_mat_demi * fft(field))
        field *= np.exp(1j * bpm.nl_mat[0, :])
        field = ifft(bpm.phase_mat * fft(field))
        field *= np.exp(1j * bpm.nl_mat[0, :])
        field = ifft(bpm.phase_mat_demi * fft(field))
        test_4 = field

        field = bpm.field
        field = ifft(bpm.phase_mat_demi * fft(field))
        field *= np.exp(1j * bpm.nl_mat[0, :])
        field = ifft(bpm.phase_mat_demi * fft(field))
        field = ifft(bpm.phase_mat_demi * fft(field))
        field *= np.exp(1j * bpm.nl_mat[0, :])
        field = ifft(bpm.phase_mat_demi * fft(field))
        test_5 = field

        plt.figure("field real 2")
        plt.title("Same algorithme optimized")
        plt.xlim(-20, 20)
        plt.ylim(-1, 20)
        plt.plot(x, test_4.real, label='dz/2+lens+dz+lens+dz/2')
        plt.plot(x, test_5.real, label='(dz/2+lens+dz/2)*2')

        plt.legend()
        plt.show()
        plt.figure("field imag 2")
        plt.title("Same algorithme optimized")
        plt.xlim(-30, 30)
        plt.plot(x, test_4.imag, label='dz/2+lens+dz+lens+dz/2')
        plt.plot(x, test_5.imag, label='(dz/2+lens+dz/2)*2')
        plt.legend()
        plt.show()

        field = bpm.field
        field = ifft(bpm.phase_mat_demi * fft(field))
        field *= np.exp(1j * bpm.nl_mat[0, :])
        field = ifft(bpm.phase_mat * fft(field))
        test_6 = field

        field = bpm.field
        field = ifft(bpm.phase_mat_demi * fft(field))
        field *= np.exp(1j * bpm.nl_mat[0, :])
        field = ifft(bpm.phase_mat_demi * fft(field))
        test_7 = field

        plt.figure("field real 3")
        plt.title("Approximation if uses loop over lens+dz")
        plt.xlim(-20, 20)
        plt.ylim(-1, 20)
        plt.plot(x, test_6.real, label='dz/2+lens+dz')
        plt.plot(x, test_7.real, label='dz/2+lens+dz/2')

        plt.legend()
        plt.show()
        plt.figure("field imag 3")
        plt.title("Approximation if uses loop over lens+dz")
        plt.xlim(-30, 30)
        plt.plot(x, test_4.imag, label='dz/2+lens+dz')
        plt.plot(x, test_5.imag, label='dz/2+lens+dz/2')
        plt.legend()
        plt.show()

    def example_kerr():
        """More test than example.
        Show the different approximation possible for the BPM implementation of the
        Kerr effect."""
        width = 6
        no = 1
        delta_no = 0.0014
        length_z = 1000
        dist_z = 0.5
        nbr_z_disp = 1
        dist_x = 0.1
        length_x = 300.8

        bpm = Bpm(width, no, delta_no,
                  length_z, dist_z, nbr_z_disp,
                  length_x, dist_x)

        [length_z, nbr_z, nbr_z_disp, length_x, nbr_x, x] = bpm.create_x_z()

        shape = bpm.gauss_guide(4)

        nbr_p = 0
        p = 0

        [peaks, dn] = bpm.create_guides(shape, nbr_p, p)

        fwhm = 6
        lo = 1.5

        field = bpm.gauss_light(fwhm)
        irrad = 20000e13  # if too high, see big difference between method
        theta_ext = 0

        [progress_pow] = bpm.init_field(field, theta_ext, irrad, lo)

        # Need to overwrite those variables due to changes
        theta = asin(sin(radians(theta_ext)) / no)  # angle in the guide
        nu_max = 1 / (2 * dist_x)  # max frequency due to sampling
        # Spacial frequencies over x (1/µm)
        nu = np.linspace(-nu_max,
                         nu_max * (1 - 2/nbr_x),
                         nbr_x)
        intermed = no * cos(theta) / lo
        fr = -2 * pi * nu**2 / (intermed + np.sqrt(
            intermed**2
            - nu**2
            + 0j))

        bpm.phase_mat = fftshift(np.exp(1j * dist_z * fr))
        bpm.phase_mat_demi = fftshift(np.exp(1j * dist_z / 2 * fr))
        # End overwrite

        kerr_loop = 3
        variance_check = False
        chi3 = 10 * 1E-20

        nbr_step = 2000  # max length_z / dist_z

        print("\n dz/2+lens+dz/2")
        field = bpm.field
        for i in range(nbr_step):
            print("step", i)
    #        plt.figure(num='Reference without kerr')
    #        ax1 = plt.subplot(211)
    #        ax2 = plt.subplot(212)
    #        ax1.set_title("real: no kerr")
    #        ax2.set_title("imag: no kerr")
    #        plt.xlim(-1, 1)
    #        plt.ylim(5.85e17, 6.05e17)

            # Linear propagation over dz/2
            field = ifft(bpm.phase_mat_demi * fft(field))

            # Influence of the index modulation on the field
            field = field * np.exp(1j * bpm.nl_mat[nbr_step, :])  # No changes if
            # no initial guide (exp=1)

            # Linear propagation over dz/2
            field = ifft(bpm.phase_mat_demi * fft(field))

            cur_pow = bpm.epnc * (field * field.conjugate()).real
    #        ax1.plot(x, field_x.real, label='no kerr')
    #        ax2.plot(x, field_x.imag, label='no kerr')

        field_ref = field
        cur_ref = cur_pow
    #    ax1.legend(loc="upper right")
    #    ax2.legend(loc="upper right")
    #    plt.show()

        print("\n dz+kerr")
        field = bpm.field
        for i in range(nbr_step):
            print("step", i)
    #        plt.figure(num='Impact of the kerr effect for dz+kerr')
    #        ax1 = plt.subplot(211)
    #        ax2 = plt.subplot(212)
    #        ax1.set_title("real: dz+kerr")
    #        ax2.set_title("imag: dz+kerr")
    #        plt.xlim(-1, 1)
    #        plt.ylim(5.85e17, 6.05e17)

            # Linear propagation over dz
            field = ifft(bpm.phase_mat * fft(field))

            # Influence of the index modulation on the field
            field_x = field * np.exp(1j * bpm.nl_mat[nbr_step, :])  # No changes if
            # no initial guide (exp=1)

            cur_pow = bpm.epnc * (field_x * field_x.conjugate()).real

    #        ax1.plot(x, field_x.real, label='no kerr')
    #        ax2.plot(x, field_x.imag, label='no kerr')

            if kerr_loop != 0:
                for k in range(1):
                    prev_pow = cur_pow
                    # influence of the beam intensity on the index modulation
                    dn = bpm.dn[nbr_step, :] + (3 * chi3 / 8 / no * prev_pow)
                    nl_mat = bpm.ko * bpm.dist_z * dn

                    # influence of the index modulation on the field
                    field_x = field * np.exp(1j * nl_mat)  # No changes for the pow

                    # power at z
                    cur_pow = bpm.epnc * (field_x * field_x.conjugate()).real

        #            ax1.plot(x, field_x.real, label='loop:'+str(k+1))
        #            ax2.plot(x, field_x.imag, label='loop:'+str(k+1))

        #        print(max(dn))
        #        if variance_check:
        #            try:
        #                bpm.variance(prev_pow, cur_pow)  # Check if converge
        #                    print(bpm.nl_control_amp)
        #            except ValueError as ex:
        #                    print(ex)
        #                print("Warning", bpm.nl_control_amp)

            field = field_x

        field_1 = field
        cur_1 = cur_pow
        dn_1 = dn
    #    ax1.legend(loc="upper right")
    #    ax2.legend(loc="upper right")
    #    plt.show()

        print("\n dz/2+kerr+dz/2")
        field = bpm.field
        for i in range(nbr_step):
            print("step", i)
    #        plt.figure(num="intensity with kerr dz/2+kerr+dz/2")
    #        ax1 = plt.subplot(211)
    #        ax2 = plt.subplot(212)
    #        ax1.set_title("real: dz/2+kerr+dz/2")
    #        ax2.set_title("imag: dz/2+kerr+dz/2")
    #        plt.xlim(-1, 1)
    #        plt.ylim(5.85e17, 6.05e17)

            # Linear propagation over dz/2
            field = ifft(bpm.phase_mat_demi * fft(field))

            # Influence of the index modulation on the field
            field_x = field * np.exp(1j * bpm.nl_mat[nbr_step, :])  # No changes if
            # no initial guide (exp=1)

            # Linear propagation over dz/2
            field_x = ifft(bpm.phase_mat_demi * fft(field_x))

            cur_pow = bpm.epnc * (field_x * field_x.conjugate()).real

    #        ax1.plot(x, field_x.real, label='no kerr')
    #        ax2.plot(x, field_x.imag, label='no kerr')

            for k in range(kerr_loop):
                prev_pow = cur_pow
                # influence of the beam intensity on the index modulation
                dn = bpm.dn[nbr_step, :] + (3 * chi3 / 8 / no * prev_pow)
                nl_mat = bpm.ko * bpm.dist_z * dn

                # influence of the index modulation on the field
                field_x = field * np.exp(1j * nl_mat)
                # Linear propagation over dz/2
                field_x = ifft(bpm.phase_mat_demi * fft(field_x))
                # power at z
                cur_pow = bpm.epnc * (field_x * field_x.conjugate()).real

    #            ax1.plot(x, field_x.real, label='loop:'+str(k+1))
    #            ax2.plot(x, field_x.imag, label='loop:'+str(k+1))

    #        print(max(dn))
            if variance_check:
                try:
                    bpm.variance(prev_pow, cur_pow)  # Check if converge
    #                    print(bpm.nl_control_amp)
                except ValueError:
                    print("Warning", bpm.nl_control_amp)

            field = field_x

        field_2 = field
        cur_2 = cur_pow
        dn_2 = dn
    #    ax1.legend(loc="upper right")
    #    ax2.legend(loc="upper right")
    #    plt.show()

        print("\n kerr+dz")
        field = bpm.field
        for i in range(nbr_step):
            print("step", i)

    #        plt.figure(num="intensity with kerr kerr+dz")
    #        ax1 = plt.subplot(211)
    #        ax2 = plt.subplot(212)
    #        ax1.set_title("real: kerr+dz")
    #        ax2.set_title("imag: kerr+dz")
    #        plt.xlim(-1, 1)
    #        plt.ylim(5.85e17, 6.05e17)

            # Influence of the index modulation on the field
            field_x = field * np.exp(1j * bpm.nl_mat[nbr_step, :])  # No changes if
            # no initial guide (exp=1)

            # Linear propagation over dz
            field_x = ifft(bpm.phase_mat * fft(field_x))

            cur_pow = bpm.epnc * (field_x * field_x.conjugate()).real

    #        ax1.plot(x, field_x.real, label='no kerr')
    #        ax2.plot(x, field_x.imag, label='no kerr')

            for k in range(kerr_loop):
                prev_pow = cur_pow
                # influence of the beam intensity on the index modulation
                dn = bpm.dn[nbr_step, :] + (3 * chi3 / 8 / no * prev_pow)
                nl_mat = bpm.ko * bpm.dist_z * dn

                # influence of the index modulation on the field
                field_x = field * np.exp(1j * nl_mat)
                # Linear propagation over dz
                field_x = ifft(bpm.phase_mat * fft(field_x))
                # power at z
                cur_pow = bpm.epnc * (field_x * field_x.conjugate()).real

    #            ax1.plot(x, field_x.real, label='loop:'+str(k+1))
    #            ax2.plot(x, field_x.imag, label='loop:'+str(k+1))

    #        print(max(dn))
            if variance_check:
                try:
                    bpm.variance(prev_pow, cur_pow)  # Check if converge
    #                    print(bpm.nl_control_amp)
                except ValueError:
                    print("Warning", bpm.nl_control_amp)

            field = field_x

        field_3 = field
        cur_3 = cur_pow
        dn_3 = dn
    #    ax1.legend(loc="upper right")
    #    plt.show()

        plt.figure(num="Impact order kerr")

        ax1 = plt.subplot(211)
        ax2 = plt.subplot(212)

        ax1.set_title("phase: comparison")
        ax2.set_title("power: comparison")

        ax1.set_xlim(-200, 200)
        ax2.set_xlim(-200, 200)

        ax1.plot(x, np.angle(field_ref), label="no kerr")
        ax1.plot(x, np.angle(field_1), label="dz+kerr")
        ax1.plot(x, np.angle(field_2), label="dz/2+kerr+dz/2")
        ax1.plot(x, np.angle(field_3), label="kerr+dz")

        ax2.plot(x, cur_ref, label="no kerr")
        ax2.plot(x, cur_1, label="dz+kerr")
        ax2.plot(x, cur_2, label="dz/2+kerr+dz/2")
        ax2.plot(x, cur_3, label="kerr+dz")

        ax1.legend(loc="upper right")
        ax2.legend(loc="upper right")

        plt.show()

        dn_ref = bpm.dn[nbr_step, :]

        plt.figure(num="Impact on dn order kerr")

        ax1 = plt.subplot(111)

        ax1.set_title("dn: comparison")

        ax1.set_xlim(-200, 200)

        ax1.plot(x, dn_ref, label="no kerr")
        ax1.plot(x, dn_1, label="dz+kerr")
        ax1.plot(x, dn_2, label="dz/2+kerr+dz/2")
        ax1.plot(x, dn_3, label="kerr+dz")

        ax1.legend(loc="upper right")

        plt.show()