/// <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_totalMass = (parms.Mass1 + parms.Mass2); m_reducedMass = (parms.Mass1 * parms.Mass2) / m_totalMass; m_potential = V; m_initialMomentum1 = new Vec2(parms.InitialWavePacketMomentum1); m_initialMomentum2 = new Vec2(parms.InitialWavePacketMomentum2); m_initialPosition1 = new Vec2(parms.InitialWavePacketCenter1); m_initialPosition2 = new Vec2(parms.InitialWavePacketCenter2); m_sigmaRel = parms.InitialWavePacketSize * Math.Sqrt(m_totalMass / m_mass2); m_sigmaCm = parms.InitialWavePacketSize * Math.Sqrt(m_mass1 / m_totalMass); m_dampingBorderWidth = parms.DampingBorderWidth; m_dampingFactor = parms.DampingFactor; 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; // 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; } } }
/// <summary> /// Damps the wavefunction amplitude near the region boundary. /// </summary> private void ApplyDamping(VisscherWf wf) { int sx = wf.GridSizeX; int sy = wf.GridSizeY; int d = m_dampingBorderWidth; float[] factors = new float[d]; for (int i = 0; i < d; i++) { factors[i] = (float)(1.0 - m_dampingFactor * m_deltaT * (1.0 - Math.Sin(((Math.PI / 2) * i) / d))); } // Top border for (int y = 0; y < d; y++) { float[] wfDataIPy = wf.ImagPartP[y]; float[] wfDataIMy = wf.ImagPartM[y]; float[] wfDataRy = wf.RealPart[y]; float f = factors[y]; for (int x = 0; x < sx; x++) { wfDataRy[x] *= f; wfDataIPy[x] *= f; wfDataIMy[x] *= f; } } // Bottom border for (int y = sy - d; y < sy; y++) { float[] wfDataIPy = wf.ImagPartP[y]; float[] wfDataIMy = wf.ImagPartM[y]; float[] wfDataRy = wf.RealPart[y]; float f = factors[sy - 1 - y]; for (int x = 0; x < sx; x++) { wfDataRy[x] *= f; wfDataIPy[x] *= f; wfDataIMy[x] *= f; } } // Left and right borders for (int y = 0; y < sy; y++) { float[] wfDataIPy = wf.ImagPartP[y]; float[] wfDataIMy = wf.ImagPartM[y]; float[] wfDataRy = wf.RealPart[y]; for (int x = 0; x < d; x++) { float f = factors[x]; wfDataRy[x] *= f; wfDataIPy[x] *= f; wfDataIMy[x] *= f; } for (int x = sx - d; x < sx; x++) { float f = factors[sx - 1 - x]; wfDataRy[x] *= f; wfDataIPy[x] *= f; wfDataIMy[x] *= f; } } }
/// <summary> /// Evolves the wavefunction by a single time step /// </summary> private void EvolveByOneTimeStep(VisscherWf wf, float[][] V) { int sx = wf.GridSizeX; int sy = wf.GridSizeY; int sxm1 = sx - 1; int sym1 = sy - 1; float keFactor = 1.0f / (2 * m_reducedMass * wf.LatticeSpacing * wf.LatticeSpacing); float alpha = 5.0f; float beta = -4.0f / 3.0f; float delta = 1.0f / 12.0f; // Compute the next real part in terms of the current imaginary part 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[] V_y = V[y]; float[] wfR_y = wf.RealPart[y]; float[] wfI_y = wf.ImagPartP[y]; float[] wfI_ym = wf.ImagPartP[ym]; float[] wfI_yp = wf.ImagPartP[yp]; float[] wfI_ymm = wf.ImagPartP[ymm]; float[] wfI_ypp = wf.ImagPartP[ypp]; for (int x = 0; x < sx; x++) { int xp = (x < sxm1) ? x + 1 : 0; int xpp = (xp < sxm1) ? xp + 1 : 0; int xm = (x > 0) ? x - 1 : sxm1; int xmm = (xm > 0) ? xm - 1 : sxm1; // A discretization of the 2nd derivative, whose error term is O(a^6) float ke = keFactor * ( alpha * wfI_y[x] + beta * (wfI_y[xm] + wfI_y[xp] + wfI_ym[x] + wfI_yp[x]) + delta * (wfI_y[xmm] + wfI_y[xpp] + wfI_ymm[x] + wfI_ypp[x]) ); float pe = V_y[x] * wfI_y[x]; wfR_y[x] += m_deltaT * (ke + 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, 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[] V_y = V[y]; float[] wfIM_y = wf.ImagPartM[y]; float[] wfIP_y = wf.ImagPartP[y]; float[] wfR_y = wf.RealPart[y]; float[] wfR_ym = wf.RealPart[ym]; float[] wfR_yp = wf.RealPart[yp]; float[] wfR_ymm = wf.RealPart[ymm]; float[] wfR_ypp = wf.RealPart[ypp]; for (int x = 0; x < sx; x++) { int xp = (x < sxm1) ? x + 1 : 0; int xpp = (xp < sxm1) ? xp + 1 : 0; int xm = (x > 0) ? x - 1 : sxm1; int xmm = (xm > 0) ? xm - 1 : sxm1; // A discretization of the 2nd derivative, whose error term is O(a^6) float ke = keFactor * ( alpha * wfR_y[x] + beta * (wfR_y[xm] + wfR_y[xp] + wfR_ym[x] + wfR_yp[x]) + delta * (wfR_y[xmm] + wfR_y[xpp] + wfR_ymm[x] + wfR_ypp[x]) ); float pe = V_y[x] * wfR_y[x]; wfIP_y[x] = wfIM_y[x] - m_deltaT * (ke + pe); } }, m_multiThread); // Optionally perform damping to suppress reflection and transmission at the borders. if ((m_dampingBorderWidth > 0) && (m_dampingFactor > 0.0f)) { ApplyDamping(wf); } }