/// <summary> /// Worker method. /// </summary> protected override void WorkerMethod() { // Precompute the potential everywhere on the grid float[][] V = PrecomputeV(0); // Create a Visscher wf from the input wf m_visscherWf = new VisscherWf(m_intialWf, V, m_particleMass, m_deltaT, m_multiThread); m_intialWf = null; // Allow m_initialWf to be garbage collected // Main loop m_currentTimeStepIndex = 0; while (m_currentTimeStepIndex < m_totalNumTimeSteps) { // Compute the potential at the current time, if necessary if (m_isTimeDependentV && (m_currentTimeStepIndex > 0)) { V = PrecomputeV(m_currentTimeStepIndex * m_deltaT); } // Evolve the wavefunction by one timestep EvolveByOneTimeStep(m_visscherWf, V); m_currentTimeStepIndex++; // Report progress to the caller if (m_currentTimeStepIndex % m_reportInterval == 0) { ReportProgress(); 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 timestep /// </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_particleMass * 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); } }