Пример #1
0
        /// <summary>
        /// Creates a Gaussian wavepacket with given properties.
        /// </summary>
        public static WaveFunction CreateGaussianWavePacket(
            int gridSizeX, int gridSizeY, float latticeSpacing, bool originAtLatticeCenter, float mass,
            Vec2 packetCenter, Vec2 packetWidth, Vec2 avgMomentum, bool multiThread = true)
        {
            WaveFunction wf = new WaveFunction(gridSizeX, gridSizeY, latticeSpacing);

            Complex I             = Complex.I;
            float   rootPi        = (float)Math.Sqrt(Math.PI);
            float   sigmaXSq      = packetWidth.X * packetWidth.X;
            float   sigmaYSq      = packetWidth.Y * packetWidth.Y;
            float   norm          = (float)Math.Sqrt((packetWidth.X / (rootPi * sigmaXSq)) * (packetWidth.Y / (rootPi * sigmaYSq)));
            int     halfGridSizeX = (gridSizeX - 1) / 2;
            int     halfGridSizeY = (gridSizeY - 1) / 2;

            TdseUtils.Misc.ForLoop(0, gridSizeY, (y) =>
            {
                float yf        = (originAtLatticeCenter) ? (y - halfGridSizeY) * latticeSpacing : (y * latticeSpacing);
                Complex expArgY = I * yf * avgMomentum.Y - (yf - packetCenter.Y) * (yf - packetCenter.Y) / (2 * sigmaYSq);

                float[] wfDataY = wf.Data[y];
                for (int x = 0; x < gridSizeX; x++)
                {
                    float xf = (originAtLatticeCenter) ? (x - halfGridSizeX) * latticeSpacing : (x * latticeSpacing);

                    Complex expArgYX = expArgY + I * xf * avgMomentum.X - (xf - packetCenter.X) * (xf - packetCenter.X) / (2 * sigmaXSq);
                    Complex wfVal    = norm * Complex.Exp(expArgYX);

                    wfDataY[2 * x]     = wfVal.Re;
                    wfDataY[2 * x + 1] = wfVal.Im;
                }
            }, multiThread);

            wf.Normalize();
            return(wf);
        }
Пример #2
0
        /// <summary>
        /// Constructor. Initializes a Visscher wavefunction from an ordinary wavefunction.
        /// </summary>
        public VisscherWf(WaveFunction inputWf, float[][] V, float mass, float dt, bool multiThread = true)
        {
            int sx = inputWf.GridSizeX;
            int sy = inputWf.GridSizeY;

            LatticeSpacing = inputWf.LatticeSpacing;

            // Allocate the arrays
            RealPart  = TdseUtils.Misc.Allocate2DArray(sy, sx);
            ImagPartM = TdseUtils.Misc.Allocate2DArray(sy, sx);
            ImagPartP = TdseUtils.Misc.Allocate2DArray(sy, sx);

            // For the real part, just copy the values from the input wavefunction.
            for (int y = 0; y < sy; y++)
            {
                float[] realPartY = RealPart[y];
                float[] inputWfY  = inputWf.Data[y];
                for (int x = 0; x < sx; x++)
                {
                    realPartY[x] = inputWfY[2 * x];
                }
            }


            // For the imaginary parts, we need to compute the time evolutions.
            // We use a power series expansion of the time-evolution operator, accurate to 2nd order in H*dt
            WaveFunction H_PsiIn  = inputWf.ApplyH(V, mass, multiThread);
            WaveFunction H2_PsiIn = H_PsiIn.ApplyH(V, mass, multiThread);

            float halfDt    = dt / 2;
            float eighthDt2 = dt * dt / 8;

            TdseUtils.Misc.ForLoop(0, sy, (y) =>
            {
                float[] imPY      = this.ImagPartP[y];
                float[] imMY      = this.ImagPartM[y];
                float[] inputWfY  = inputWf.Data[y];
                float[] H_PsiInY  = H_PsiIn.Data[y];
                float[] H2_PsiInY = H2_PsiIn.Data[y];

                for (int x = 0; x < sx; x++)
                {
                    int x2   = 2 * x;
                    int x2p1 = x2 + 1;

                    float dt0Term = inputWfY[x2p1];
                    float dt1Term = halfDt * H_PsiInY[x2];
                    float dt2Term = eighthDt2 * H2_PsiInY[x2p1];

                    imPY[x] = dt0Term - dt1Term - dt2Term; // [1 - i*H*(dt/2) - (1/2)H^2*(dt/2)^2] * Psi
                    imMY[x] = dt0Term + dt1Term - dt2Term; // [1 + i*H*(dt/2) - (1/2)H^2*(dt/2)^2] * Psi
                }
            }, multiThread);
        }
Пример #3
0
        /// <summary>
        /// Converts a Visscher wavefunction to a regular wavefunction.
        /// </summary>
        public WaveFunction ToRegularWavefunction(bool multiThread = true)
        {
            int sx = GridSizeX;
            int sy = GridSizeY;

            WaveFunction result = new WaveFunction(sx, sy, LatticeSpacing);

            TdseUtils.Misc.ForLoop(0, sy, (y) =>
            {
                float[] thisRy  = RealPart[y];
                float[] thisIMy = ImagPartM[y];
                float[] thisIPy = ImagPartP[y];
                float[] outWfy  = result.Data[y];

                for (int x = 0; x < sx; x++)
                {
                    outWfy[2 * x] = thisRy[x];

                    // Take the square root of Im(t-dt/2) * I(t+dt/2), as this is the quantity that gives a conserved probability.
                    float IM       = thisIMy[x];
                    float IP       = thisIPy[x];
                    float Iproduct = IM * IP;

                    float Iout;
                    if (Iproduct > 0.0f)
                    {
                        Iout = (float)Math.Sqrt(Iproduct);
                        if (IM < 0.0f)
                        {
                            Iout = -Iout;
                        }
                    }
                    else
                    {
                        Iout = 0.0f;
                    }

                    outWfy[2 * x + 1] = Iout;
                }
            }, multiThread);

            return(result);
        }
Пример #4
0
        /// <summary>
        /// Worker method.
        /// </summary>
        protected override void WorkerMethod()
        {
            // Reset counters
            m_currentTimeStepIndex = 0;
            m_lastSavedFrame       = -1;

            // Precompute the potential everywhere on the grid
            float[][] V = PrecomputeV();

            // Create the initial relative wavefunction
            Vec2 r0 = m_initialPosition1 - m_initialPosition2;
            Vec2 p0 = (m_mass2 / m_totalMass) * m_initialMomentum1 - (m_mass1 / m_totalMass) * m_initialMomentum2;
            int  sx = 2 * m_gridSizeX - 1; // The range of r = r1-r2 is twice the range of r1, r2
            int  sy = 2 * m_gridSizeY - 1;

            WaveFunction initialWf = WaveFunctionUtils.CreateGaussianWavePacket(
                sx, sy, m_latticeSpacing, true, m_reducedMass, r0, m_sigmaRel, p0, m_multiThread
                );

            m_visscherWf = new VisscherWf(initialWf, V, m_reducedMass, m_deltaT, m_multiThread);
            initialWf    = null; // Allow initialWf to be garbage collected
            TimeStepCompleted();
            if (IsCancelled)
            {
                return;
            }


            // Main loop: Evolve the relative wavefunction
            while (m_currentTimeStepIndex < m_totalNumTimeSteps)
            {
                // Evolve the wavefunction by one timestep
                EvolveByOneTimeStep(m_visscherWf, V);
                m_currentTimeStepIndex++;

                // Report progress to the client
                TimeStepCompleted();
                if (IsCancelled)
                {
                    return;
                }
            }
        }
Пример #5
0
        /// <summary>
        /// Computes the result of applying a given Hamiltonian operator to this wavefunction.
        /// </summary>
        public WaveFunction ApplyH(float[][] V, float mass, bool multiThread = true)
        {
            // Initialize locals
            int sx    = GridSizeX;
            int sy    = GridSizeY;
            int sxm1  = sx - 1;
            int sym1  = sy - 1;
            int sxm2  = sx - 2;
            int sym2  = sy - 2;
            int sx2   = 2 * sx;
            int sx2m2 = sx2 - 2;

            float keFactor = 1.0f / (2 * mass * m_latticeSpacing * m_latticeSpacing);

            float alpha = 5.0f;
            float beta  = -4.0f / 3.0f;
            float delta = 1.0f / 12.0f;

            WaveFunction outWf = new WaveFunction(sx, sy, m_latticeSpacing);


            // Compute H * Wf
            TdseUtils.Misc.ForLoop(0, sy, (y) =>
            {
                int yp  = (y < sym1) ?  y + 1 : 0;
                int ypp = (yp < sym1) ? yp + 1 : 0;
                int ym  = (y > 0) ?  y - 1 : sym1;
                int ymm = (ym > 0) ? ym - 1 : sym1;

                float[] inWf_y   = m_data[y];
                float[] inWf_ym  = m_data[ym];
                float[] inWf_yp  = m_data[yp];
                float[] inWf_ymm = m_data[ymm];
                float[] inWf_ypp = m_data[ypp];
                float[] outWf_y  = outWf.m_data[y];
                float[] V_y      = V[y];

                for (int rx = 0; rx < sx2; rx += 2)
                {
                    int rxp  = (rx < sx2m2) ?  rx + 2  : 0;
                    int rxpp = (rxp < sx2m2) ?  rxp + 2 : 0;
                    int rxm  = (rx > 0) ?  rx - 2 : sx2m2;
                    int rxmm = (rxm > 0) ? rxm - 2 : sx2m2;
                    int x    = rx / 2;

                    // Kinetic energy terms.
                    float kR = keFactor * (
                        alpha * inWf_y[rx] +
                        beta * (inWf_y[rxm] + inWf_y[rxp] + inWf_ym[rx] + inWf_yp[rx]) +
                        delta * (inWf_y[rxmm] + inWf_y[rxpp] + inWf_ymm[rx] + inWf_ypp[rx])
                        );

                    int ix   = rx + 1;
                    float kI = keFactor * (
                        alpha * inWf_y[ix] +
                        beta * (inWf_y[rxm + 1] + inWf_y[rxp + 1] + inWf_ym[ix] + inWf_yp[ix]) +
                        delta * (inWf_y[rxmm + 1] + inWf_y[rxpp + 1] + inWf_ymm[ix] + inWf_ypp[ix])
                        );

                    // Potential energy terms
                    float vR = V_y[x] * inWf_y[rx];
                    float vI = V_y[x] * inWf_y[ix];

                    outWf_y[rx] = kR + vR;
                    outWf_y[ix] = kI + vI;
                }
            }, multiThread);

            return(outWf);
        }