/// <summary> /// Computes a 2D harmonic oscillator wavefunction with given quantum numbers. /// </summary> public static WaveFunction2D1P GetSHOWaveFunction( int gridSizeX, int gridSizeY, float latticeSpacing, float mass, Vec2 packetCenter, float sigma, int N, int Lz, bool multiThread = true) { // Check the input if ((N < 0) || (Lz > N) || (Lz < -N) || ((N + Lz) % 2) != 0) { throw new ArgumentException("Invalid (N,m) in WaveFunctionUtils.GetSHOWaveFunction."); } EigenSystem hamX = Diagonalized1dShoHamiltonian(mass, sigma, packetCenter.X, latticeSpacing, gridSizeX); EigenSystem hamY = Diagonalized1dShoHamiltonian(mass, sigma, packetCenter.Y, latticeSpacing, gridSizeY); Vector eivcX0 = hamX.EigenVector(0); Vector eivcY0 = hamY.EigenVector(0); WaveFunction2D1P result; if ((N == 0) && (Lz == 0)) { result = DirectProduct(hamX.EigenVector(0), hamY.EigenVector(0), latticeSpacing); } else if ((N == 1) && (Lz == 1)) { WaveFunction2D1P psi_10 = DirectProduct(hamX.EigenVector(1), hamY.EigenVector(0), latticeSpacing); WaveFunction2D1P psi_01 = DirectProduct(hamX.EigenVector(0), hamY.EigenVector(1), latticeSpacing); result = psi_10 + Complex.I * psi_01; } else if ((N == 2) && (Lz == 0)) { WaveFunction2D1P psi_20 = DirectProduct(hamX.EigenVector(2), hamY.EigenVector(0), latticeSpacing); WaveFunction2D1P psi_02 = DirectProduct(hamX.EigenVector(0), hamY.EigenVector(2), latticeSpacing); result = psi_20 + psi_02; } else if ((N == 2) && (Lz == 2)) { WaveFunction2D1P psi_11 = DirectProduct(hamX.EigenVector(1), hamY.EigenVector(1), latticeSpacing); WaveFunction2D1P psi_20 = DirectProduct(hamX.EigenVector(2), hamY.EigenVector(0), latticeSpacing); WaveFunction2D1P psi_02 = DirectProduct(hamX.EigenVector(0), hamY.EigenVector(2), latticeSpacing); result = psi_20 - psi_02 + (Math.Sqrt(2) * Complex.I) * psi_11; } else { throw new ArgumentException("Invalid (N,Lz) in WaveFunctionUtils.GetSHOWaveFunction."); } result.Normalize(); return(result); }
/// <summary> /// Worker method. /// </summary> protected override void WorkerMethod() { // Reset counters m_currentTimeStepIndex = 0; m_lastSavedFrame = -1; // Create a single-particle wf representing the incoming wavepacket WaveFunction2D1P initialWf1 = TdseSolver_2D1P.WaveFunctionUtils.CreateGaussianWavePacket(m_gridSizeX, m_gridSizeY, m_latticeSpacing, m_mass1, m_initialPosition1.ToPointF(), m_initialSize1.ToPointF(), m_initialMomentum1.ToPointF(), m_multiThread ); // Create a single-particle wf representing the stationary bound state WaveFunction2D1P initialWf2 = WaveFunctionUtils.GetSHOWaveFunction(m_gridSizeX, m_gridSizeY, m_latticeSpacing, m_mass2, m_initialPosition2, m_sho_sigma, m_sho_N, m_sho_Lz, m_multiThread); // Precompute the potentials everywhere on the grid float[][] V1 = TdseUtils.Misc.Allocate2DArray(m_gridSizeY, m_gridSizeX); float[][] V2 = PrecomputeV2(); // Create a VisscherWf from the direct product of the 1-particle wfs m_visscherWf = new VisscherWf(initialWf1, initialWf2, V1, V2, m_mass1, m_mass2, m_deltaT, m_multiThread); TimeStepCompleted(); if (IsCancelled) { return; } float[][] Vrel = PrecomputeVrel(); // Main loop: Evolve the relative wavefunction while (m_currentTimeStepIndex < m_totalNumTimeSteps) { // Evolve the wavefunction by one timestep EvolveByOneTimeStep(m_visscherWf, Vrel, V2); m_currentTimeStepIndex++; // Report progress to the client TimeStepCompleted(); if (IsCancelled) { return; } } }
/// <summary> /// Forms the direct product of two wavefunctions /// </summary> private static WaveFunction2D1P DirectProduct(Vector wfx, Vector wfy, float latticeSpacing) { // Construct the 2D wavefunction int sx = wfx.Length; int sy = wfy.Length; WaveFunction2D1P wfdp = new WaveFunction2D1P(sx, sy, latticeSpacing); for (int y = 0; y < sy; y++) { double wfyValue = wfy[y]; float[] wfdpDataY = wfdp.Data[y]; for (int x = 0; x < sx; x++) { double wfxValue = wfx[x]; wfdpDataY[2 * x] = (float)(wfxValue * wfyValue); wfdpDataY[2 * x + 1] = 0.0f; } } return(wfdp); }
/// <summary> /// Constructor. Initializes a Visscher wavefunction from a direct product of two ordinary wavefunctions. /// </summary> public VisscherWf(WaveFunction2D1P inputWf1, WaveFunction2D1P inputWf2, float[][] V1, float[][] V2, float mass1, float mass2, float dt, bool multiThread = true) { int sx = inputWf1.GridSizeX; int sy = inputWf1.GridSizeY; LatticeSpacing = inputWf1.LatticeSpacing; // Allocate the arrays RealPart = TdseUtils.Misc.Allocate4DArray(sy, sx, sy, sx); ImagPartM = TdseUtils.Misc.Allocate4DArray(sy, sx, sy, sx); ImagPartP = TdseUtils.Misc.Allocate4DArray(sy, sx, sy, sx); // Get the real part of the total wf from the direct product of wf1*wf2, at time 0 TdseUtils.Misc.ForLoop(0, sy, y2 => { for (int x2 = 0; x2 < sx; x2++) { float[][] RealPart_y2_x2 = RealPart[y2][x2]; float wf2_y2_x2r = inputWf2.Data[y2][2 * x2]; float wf2_y2_x2i = inputWf2.Data[y2][2 * x2 + 1]; for (int y1 = 0; y1 < sy; y1++) { float[] wf1_y1 = inputWf1.Data[y1]; for (int x1 = 0; x1 < sx; x1++) { RealPart_y2_x2[y1][x1] = wf1_y1[2 * x1] * wf2_y2_x2r - wf1_y1[2 * x1 + 1] * wf2_y2_x2i; } } } }, multiThread); // Get the imaginary parts of the total wf from the direct product of wf1*wf2, at time +/- dt. // To compute the latter, use a power series expansion of the time-evolution operator, accurate to 2nd order in H*dt if (V1 == null) { V1 = TdseUtils.Misc.Allocate2DArray(sy, sx); } // Set V1 to zero WaveFunction2D1P H_Wf1 = inputWf1.ApplyH(V1, mass1, multiThread); WaveFunction2D1P H2_Wf1 = H_Wf1.ApplyH(V1, mass1, multiThread); WaveFunction2D1P Wf1_Adv = inputWf1 + (dt / 2) * H_Wf1 + (dt * dt / 8) * H2_Wf1; WaveFunction2D1P Wf1_Ret = inputWf1 - (dt / 2) * H_Wf1 + (dt * dt / 8) * H2_Wf1; if (V2 == null) { V2 = TdseUtils.Misc.Allocate2DArray(sy, sx); } // Set V2 to zero WaveFunction2D1P H_Wf2 = inputWf2.ApplyH(V2, mass2, multiThread); WaveFunction2D1P H2_Wf2 = H_Wf2.ApplyH(V2, mass2, multiThread); WaveFunction2D1P Wf2_Adv = inputWf2 + (dt / 2) * H_Wf2 + (dt * dt / 8) * H2_Wf2; WaveFunction2D1P Wf2_Ret = inputWf2 - (dt / 2) * H_Wf2 + (dt * dt / 8) * H2_Wf2; TdseUtils.Misc.ForLoop(0, sy, y2 => { for (int x2 = 0; x2 < sx; x2++) { float[][] ImagPartP_y2_x2 = ImagPartP[y2][x2]; float[][] ImagPartM_y2_x2 = ImagPartM[y2][x2]; float wf2adv_y2_x2r = Wf2_Adv.Data[y2][2 * x2]; float wf2adv_y2_x2i = Wf2_Adv.Data[y2][2 * x2 + 1]; float wf2ret_y2_x2r = Wf2_Ret.Data[y2][2 * x2]; float wf2ret_y2_x2i = Wf2_Ret.Data[y2][2 * x2 + 1]; for (int y1 = 0; y1 < sy; y1++) { float[] wf1adv_y1 = Wf1_Adv.Data[y1]; float[] wf1ret_y1 = Wf1_Ret.Data[y1]; for (int x1 = 0; x1 < sx; x1++) { ImagPartP_y2_x2[y1][x1] = wf1adv_y1[2 * x1 + 1] * wf2adv_y2_x2r + wf1adv_y1[2 * x1] * wf2adv_y2_x2i; ImagPartM_y2_x2[y1][x1] = wf1ret_y1[2 * x1 + 1] * wf2ret_y2_x2r + wf1ret_y1[2 * x1] * wf2ret_y2_x2i; } } } }, multiThread); }