Exemplo n.º 1
0
    def setup_bloch_propagator(self):
        """
        Pre-calculate exponents used for the split operator propagation
        """
        v = (self.v if self.time_independent_v else partial(self.v, t=self.t))
        k = (self.k if self.time_independent_k else partial(self.k, t=self.t))

        # Get the sum of the potential energy contributions
        self.bloch_expV = -0.25 * self.dbeta * (v(self.x - 0.5 * self.Theta) +
                                                v(self.x + 0.5 * self.Theta))

        # Make sure that the largest value is zero
        self.bloch_expV -= self.bloch_expV.max()

        # such that the following exponent is never larger then one
        np.exp(self.bloch_expV, out=self.bloch_expV)

        # Get the sum of the kinetic energy contributions
        self.bloch_expK = -0.5 * self.dbeta * (k(self.p + 0.5 * self.Lambda) +
                                               k(self.p - 0.5 * self.Lambda))

        # Make sure that the largest value is zero
        self.bloch_expK -= self.bloch_expK.max()

        # such that the following exponent is never larger then one
        np.exp(self.bloch_expK, out=self.bloch_expK)

        # Initialize the Wigner function as the infinite temperature Gibbs state
        self.set_wignerfunction(lambda x, p: 1. + 0. * x + 0. * p)
    def setup_bloch_propagator(self):
        """
        Pre-calculate exponents used for the split operator propagation
        """
        # Get the sum of the potential energy contributions
        self.bloch_expV = ne.evaluate(
            "-0.25 * dbeta *( ({V_minus}) + ({V_plus}) )".format(
                V_minus=self.V.format(X="(X - 0.5 * Theta)"),
                V_plus=self.V.format(X="(X + 0.5 * Theta)"),
            ),
            local_dict=vars(self))

        # Make sure that the largest value is zero
        self.bloch_expV -= self.bloch_expV.max()

        # such that the following exponent is never larger then one
        np.exp(self.bloch_expV, out=self.bloch_expV)

        # Get the sum of the kinetic energy contributions
        self.bloch_expK = ne.evaluate(
            "-0.5 * dbeta *( ({K_plus}) + ({K_minus}) )".format(
                K_plus=self.K.format(P="(P + 0.5 * Lambda)"),
                K_minus=self.K.format(P="(P - 0.5 * Lambda)")),
            local_dict=vars(self))

        # Make sure that the largest value is zero
        self.bloch_expK -= self.bloch_expK.max()

        # such that the following exponent is never larger then one
        np.exp(self.bloch_expK, out=self.bloch_expK)

        # Initialize the Wigner function as the infinite temperature Gibbs state
        self.set_wignerfunction("1. + 0. * X + 0. * P")
    def set_quantum_sys(self):
        """
        Initialize quantum propagator
        :param self:
        :return:
        """
        omega = 1.

        self.quant_sys = SplitOpWignerMoyal(
            t=0,
            dt=0.05,
            x_grid_dim=256,
            x_amplitude=10.,
            p_grid_dim=256,
            p_amplitude=10.,

            # kinetic energy part of the hamiltonian
            k=lambda p: 0.5 * p**2,

            # potential energy part of the hamiltonian
            v=lambda x: 0.5 * (omega * x)**2,

            # these functions are used for evaluating the Ehrenfest theorems
            x_rhs=lambda p: p,
            p_rhs=lambda x, p: -omega**2 * x,
        )

        # set randomised initial condition
        sigma = np.random.uniform(1., 3.)
        p0 = np.random.uniform(-3., 3.)
        x0 = np.random.uniform(-3., 3.)

        self.quant_sys.set_wignerfunction(lambda x, p: np.exp(-sigma * (
            x - x0)**2 - (1. / sigma) * (p - p0)**2))
Exemplo n.º 4
0
    def __init__(self, *, D=0, gamma=0, **kwargs):
        """
        :param D: the dephasing coefficient (see Eq. (36) in Ref. [*])
        :param gamma: the decay coefficient (see Eq. (62) in Ref. [*])
        :param kwargs: parameters passed to the parent class
        """
        # initialize the parent class
        SplitOpWignerMoyal.__init__(self, **kwargs)

        # save new parameters
        self.D = D
        self.gamma = gamma

        # if the dephasing term is nonzero, modify the potential energy phase
        # Note that the dephasing term does not modify the Ehrenfest theorems
        if D:
            # introduce some aliases
            v = self.v
            x = self.x
            dt = self.dt
            Theta = self.Theta

            # Introduce the action of the dephasing term by redefining the potential term
            if self.time_independent_v:
                # pre-calculate the potential dependent phase since it is time-independent
                _expV = np.exp(-0.5j * dt *
                               (v(x - 0.5 * Theta) - v(x + 0.5 * Theta)) -
                               0.5 * dt * D * Theta**2)

                @njit
                def expV(wignerfunction, t):
                    wignerfunction *= _expV

            else:
                # the phase factor is time-dependent
                @njit
                def expV(wignerfunction, t):
                    wignerfunction *= np.exp(
                        -0.5j * dt *
                        (v(x - 0.5 * Theta, t) - v(x + 0.5 * Theta, t) -
                         0.5 * dt * D * Theta**2))

            self.expV = expV

        # if the decay term is nonzero, prepare for
        if gamma:

            # allocate an array for the extra copy of the Wigner function, i.e., for W^{(1)} in Eq. (63) of Ref. [*]
            self.wigner_1 = pyfftw.empty_aligned(
                self.wignerfunction.shape, dtype=self.wignerfunction.dtype)

            # p x -> theta x for self.wigner_1
            self.wigner_1_transform_p2theta = pyfftw.builders.rfft(
                self.wigner_1, axis=0, **self.fft_params)

            # theta x  ->  p x for self.wigner_1
            self.wigner_1_transform_theta2p = pyfftw.builders.irfft(
                self.wigner_1_transform_p2theta(), axis=0, **self.fft_params)
    def setup_bloch_propagator(self):
        """
        Pre-calculate exponents used for the split operator propagation
        """
        # Get the sum of the potential energy contributions
        self.bloch_expV = ne.evaluate(
            "-0.25 * dbeta *( ({V_minus}) + ({V_plus}) )".format(
                V_minus=self.V.format(X="(X - 0.5 * Theta)"),
                V_plus=self.V.format(X="(X + 0.5 * Theta)"),
            ),
            local_dict=vars(self)
        )

        # Make sure that the largest value is zero
        self.bloch_expV -= self.bloch_expV.max()

        # such that the following exponent is never larger then one
        np.exp(self.bloch_expV, out=self.bloch_expV)

        # Get the sum of the kinetic energy contributions
        self.bloch_expK = ne.evaluate(
            "-0.5 * dbeta *( ({K_plus}) + ({K_minus}) )".format(
                K_plus=self.K.format(P="(P + 0.5 * Lambda)"),
                K_minus=self.K.format(P="(P - 0.5 * Lambda)")
            ),
            local_dict=vars(self)
        )

        # Make sure that the largest value is zero
        self.bloch_expK -= self.bloch_expK.max()

        # such that the following exponent is never larger then one
        np.exp(self.bloch_expK, out=self.bloch_expK)

        # Initialize the Wigner function as the infinite temperature Gibbs state
        self.set_wignerfunction("1. + 0. * X + 0. * P")
Exemplo n.º 6
0
 def expV(wignerfunction, t):
     wignerfunction *= np.exp(
         -0.5j * dt *
         (v(x - 0.5 * Theta, t) - v(x + 0.5 * Theta, t) -
          0.5 * dt * D * Theta**2))