/// <summary> /// Constructor. /// </summary> public Evolver(RunParams parms, VDelegate V, string outputDir) { m_gridSizeX = parms.GridSize.Width; m_gridSizeY = parms.GridSize.Height; m_latticeSpacing = parms.LatticeSpacing; m_totalTime = parms.TotalTime; m_deltaT = parms.TimeStep; m_totalNumTimeSteps = (int)Math.Round(parms.TotalTime / parms.TimeStep) + 1; m_currentTimeStepIndex = 0; m_mass1 = parms.Mass1; m_mass2 = parms.Mass2; m_potential = V; m_initialMomentum1 = new Vec2(parms.InitialWavePacketMomentum1); m_initialPosition1 = new Vec2(parms.InitialWavePacketCenter1); m_initialSize1 = new Vec2(parms.InitialWavePacketSize); m_initialPosition2 = new Vec2(parms.AtomCenter); m_sho_sigma = parms.AtomSize; m_sho_N = parms.Atom_N; m_sho_Lz = parms.Atom_Lz; m_numFramesToSave = parms.NumFramesToSave; m_lastSavedFrame = -1; m_outputDir = outputDir; m_multiThread = parms.MultiThread; m_visscherWf = null; }
/// <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> /// Evolves the wavefunction by a single time step /// </summary> private void EvolveByOneTimeStep(VisscherWf wf, float[][] Vrel, float[][] V2) { // Initialize locals int sx = m_gridSizeX; int sy = m_gridSizeY; int sxm1 = sx - 1; int sym1 = sy - 1; float alpha = 5.0f; float beta = -4.0f / 3.0f; float delta = 1.0f / 12.0f; float keFactor1 = 1.0f / (2 * m_mass1 * m_latticeSpacing * m_latticeSpacing); float keFactor2 = 1.0f / (2 * m_mass2 * m_latticeSpacing * m_latticeSpacing); // Compute the next real part in terms of the current imaginary part TdseUtils.Misc.ForLoop(0, sy, (y2) => { int y2p = (y2 < sym1) ? y2 + 1 : 0; int y2pp = (y2p < sym1) ? y2p + 1 : 0; int y2m = (y2 > 0) ? y2 - 1 : sym1; int y2mm = (y2m > 0) ? y2m - 1 : sym1; for (int x2 = 0; x2 < sx; x2++) { int x2p = (x2 < sxm1) ? x2 + 1 : 0; int x2pp = (x2p < sxm1) ? x2p + 1 : 0; int x2m = (x2 > 0) ? x2 - 1 : sxm1; int x2mm = (x2m > 0) ? x2m - 1 : sxm1; for (int y1 = 0; y1 < sy; y1++) { int y1p = (y1 < sym1) ? y1 + 1 : 0; int y1pp = (y1p < sym1) ? y1p + 1 : 0; int y1m = (y1 > 0) ? y1 - 1 : sym1; int y1mm = (y1m > 0) ? y1m - 1 : sym1; float[] wfi_y2_x2_y1 = wf.ImagPartP[y2][x2][y1]; float[] wfi_y2_x2_y1m = wf.ImagPartP[y2][x2][y1m]; float[] wfi_y2_x2_y1p = wf.ImagPartP[y2][x2][y1p]; float[] wfi_y2_x2_y1mm = wf.ImagPartP[y2][x2][y1mm]; float[] wfi_y2_x2_y1pp = wf.ImagPartP[y2][x2][y1pp]; float[] wfi_y2_x2p_y1 = wf.ImagPartP[y2][x2p][y1]; float[] wfi_y2_x2m_y1 = wf.ImagPartP[y2][x2m][y1]; float[] wfi_y2_x2mm_y1 = wf.ImagPartP[y2][x2mm][y1]; float[] wfi_y2_x2pp_y1 = wf.ImagPartP[y2][x2pp][y1]; float[] wfi_y2m_x2_y1 = wf.ImagPartP[y2m][x2][y1]; float[] wfi_y2p_x2_y1 = wf.ImagPartP[y2p][x2][y1]; float[] wfi_y2mm_x2_y1 = wf.ImagPartP[y2mm][x2][y1]; float[] wfi_y2pp_x2_y1 = wf.ImagPartP[y2pp][x2][y1]; float[] wfr_y2_x2_y1 = wf.RealPart[y2][x2][y1]; for (int x1 = 0; x1 < sx; x1++) { int x1p = (x1 < sxm1) ? x1 + 1 : 0; int x1pp = (x1p < sxm1) ? x1p + 1 : 0; int x1m = (x1 > 0) ? x1 - 1 : sxm1; int x1mm = (x1m > 0) ? x1m - 1 : sxm1; // Kinetic energy float ke1 = keFactor1 * ( alpha * wfi_y2_x2_y1[x1] + beta * (wfi_y2_x2_y1[x1m] + wfi_y2_x2_y1[x1p] + wfi_y2_x2_y1m[x1] + wfi_y2_x2_y1p[x1]) + delta * (wfi_y2_x2_y1[x1mm] + wfi_y2_x2_y1[x1pp] + wfi_y2_x2_y1mm[x1] + wfi_y2_x2_y1pp[x1]) ); float ke2 = keFactor2 * ( alpha * wfi_y2_x2_y1[x1] + beta * (wfi_y2_x2m_y1[x1] + wfi_y2_x2p_y1[x1] + wfi_y2m_x2_y1[x1] + wfi_y2p_x2_y1[x1]) + delta * (wfi_y2_x2mm_y1[x1] + wfi_y2_x2pp_y1[x1] + wfi_y2mm_x2_y1[x1] + wfi_y2pp_x2_y1[x1]) ); // Potential energy float pe = (V2[y2][x2] + Vrel[y2 - y1 + sym1][x2 - x1 + sxm1]) * wfi_y2_x2_y1[x1]; wfr_y2_x2_y1[x1] += m_deltaT * (ke1 + ke2 + pe); } } } }, m_multiThread); // Swap prev and post imaginary parts float[][][][] temp = wf.ImagPartM; wf.ImagPartM = wf.ImagPartP; wf.ImagPartP = temp; // Compute the next imaginary part in terms of the current real part TdseUtils.Misc.ForLoop(0, sy, (y2) => { int y2p = (y2 < sym1) ? y2 + 1 : 0; int y2pp = (y2p < sym1) ? y2p + 1 : 0; int y2m = (y2 > 0) ? y2 - 1 : sym1; int y2mm = (y2m > 0) ? y2m - 1 : sym1; for (int x2 = 0; x2 < sx; x2++) { int x2p = (x2 < sxm1) ? x2 + 1 : 0; int x2pp = (x2p < sxm1) ? x2p + 1 : 0; int x2m = (x2 > 0) ? x2 - 1 : sxm1; int x2mm = (x2m > 0) ? x2m - 1 : sxm1; for (int y1 = 0; y1 < sy; y1++) { int y1p = (y1 < sym1) ? y1 + 1 : 0; int y1pp = (y1p < sym1) ? y1p + 1 : 0; int y1m = (y1 > 0) ? y1 - 1 : sym1; int y1mm = (y1m > 0) ? y1m - 1 : sym1; float[] wfr_y2_x2_y1 = wf.RealPart[y2][x2][y1]; float[] wfr_y2_x2_y1m = wf.RealPart[y2][x2][y1m]; float[] wfr_y2_x2_y1p = wf.RealPart[y2][x2][y1p]; float[] wfr_y2_x2_y1mm = wf.RealPart[y2][x2][y1mm]; float[] wfr_y2_x2_y1pp = wf.RealPart[y2][x2][y1pp]; float[] wfr_y2_x2p_y1 = wf.RealPart[y2][x2p][y1]; float[] wfr_y2_x2m_y1 = wf.RealPart[y2][x2m][y1]; float[] wfr_y2_x2mm_y1 = wf.RealPart[y2][x2mm][y1]; float[] wfr_y2_x2pp_y1 = wf.RealPart[y2][x2pp][y1]; float[] wfr_y2m_x2_y1 = wf.RealPart[y2m][x2][y1]; float[] wfr_y2p_x2_y1 = wf.RealPart[y2p][x2][y1]; float[] wfr_y2mm_x2_y1 = wf.RealPart[y2mm][x2][y1]; float[] wfr_y2pp_x2_y1 = wf.RealPart[y2pp][x2][y1]; for (int x1 = 0; x1 < sx; x1++) { int x1p = (x1 < sxm1) ? x1 + 1 : 0; int x1pp = (x1p < sxm1) ? x1p + 1 : 0; int x1m = (x1 > 0) ? x1 - 1 : sxm1; int x1mm = (x1m > 0) ? x1m - 1 : sxm1; // Kinetic energy float ke1 = keFactor1 * ( alpha * wfr_y2_x2_y1[x1] + beta * (wfr_y2_x2_y1[x1m] + wfr_y2_x2_y1[x1p] + wfr_y2_x2_y1m[x1] + wfr_y2_x2_y1p[x1]) + delta * (wfr_y2_x2_y1[x1mm] + wfr_y2_x2_y1[x1pp] + wfr_y2_x2_y1mm[x1] + wfr_y2_x2_y1pp[x1]) ); float ke2 = keFactor2 * ( alpha * wfr_y2_x2_y1[x1] + beta * (wfr_y2_x2m_y1[x1] + wfr_y2_x2p_y1[x1] + wfr_y2m_x2_y1[x1] + wfr_y2p_x2_y1[x1]) + delta * (wfr_y2_x2mm_y1[x1] + wfr_y2_x2pp_y1[x1] + wfr_y2mm_x2_y1[x1] + wfr_y2pp_x2_y1[x1]) ); // Potential energy float pe = (V2[y2][x2] + Vrel[y2 - y1 + sym1][x2 - x1 + sxm1]) * wfr_y2_x2_y1[x1]; wf.ImagPartP[y2][x2][y1][x1] = wf.ImagPartM[y2][x2][y1][x1] - m_deltaT * (ke1 + ke2 + pe); } } } }, m_multiThread); }