/// <summary> /// Calculates the value of a (freely evolving) Gaussian wavepacket at a given location and time. /// </summary> public static Complex FreeGaussianWavePacketValue(float x, float y, float z, float t, Vec3 initialCenter, Vec3 initialWidth, Vec3 avgMomentum, float mass) { Complex I = Complex.I; Complex effSigmaXSq = initialWidth.X * initialWidth.X + I * (t / mass); Complex effSigmaYSq = initialWidth.Y * initialWidth.Y + I * (t / mass); Complex effSigmaZSq = initialWidth.Z * initialWidth.Z + I * (t / mass); float xRel = x - initialCenter.X - avgMomentum.X * t / mass; float yRel = y - initialCenter.Y - avgMomentum.Y * t / mass; float zRel = z - initialCenter.Z - avgMomentum.Z * t / mass; float avgMomentumSq = avgMomentum.NormSq(); Complex expArg = I * (x * avgMomentum.X + y * avgMomentum.Y + z * avgMomentum.Z) - I * t * avgMomentumSq / (2 * mass) - (xRel * xRel) / (2 * effSigmaXSq) - (yRel * yRel) / (2 * effSigmaYSq) - (zRel * zRel) / (2 * effSigmaZSq); float rootPi = (float)Math.Sqrt(Math.PI); Complex normX = Complex.Sqrt(initialWidth.X / (rootPi * effSigmaXSq)); Complex normY = Complex.Sqrt(initialWidth.Y / (rootPi * effSigmaYSq)); Complex normZ = Complex.Sqrt(initialWidth.Z / (rootPi * effSigmaZSq)); Complex wfVal = normX * normY * normZ * Complex.Exp(expArg); return(wfVal); }
/// <summary> /// Constructor. /// </summary> public Evolver(RunParams parms, VDelegate V, string outputDir) { m_gridSizeX = parms.GridSpec.SizeX; m_gridSizeY = parms.GridSpec.SizeY; m_gridSizeZ = parms.GridSpec.SizeZ; 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 Vec3(parms.InitialWavePacketMomentum1); m_initialMomentum2 = new Vec3(parms.InitialWavePacketMomentum2); m_initialPosition1 = new Vec3(parms.InitialWavePacketCenter1); m_initialPosition2 = new Vec3(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> /// Creates a Gaussian wavepacket with given properties. /// </summary> public static WaveFunction CreateGaussianWavePacket( GridSpec gridSpec, float latticeSpacing, bool originAtLatticeCenter, float mass, Vec3 packetCenter, Vec3 packetWidth, Vec3 avgMomentum, bool multiThread = true) { WaveFunction wf = new WaveFunction(gridSpec, latticeSpacing); int sx = gridSpec.SizeX; int sy = gridSpec.SizeY; int sz = gridSpec.SizeZ; float[][][] wfData = wf.Data; Complex I = Complex.I; float rootPi = (float)Math.Sqrt(Math.PI); float sigmaXSq = packetWidth.X * packetWidth.X; float sigmaYSq = packetWidth.Y * packetWidth.Y; float sigmaZSq = packetWidth.Z * packetWidth.Z; float norm = (float)Math.Sqrt(1.0 / (rootPi * packetWidth.X * rootPi * packetWidth.Y * rootPi * packetWidth.Z)); int halfGridSizeX = (sx - 1) / 2; int halfGridSizeY = (sy - 1) / 2; int halfGridSizeZ = (sz - 1) / 2; TdseUtils.Misc.ForLoop(0, sz, (z) => { float zf = (originAtLatticeCenter) ? (z - halfGridSizeZ) * latticeSpacing : (z * latticeSpacing); Complex expArgZ = I * zf * avgMomentum.Z - (zf - packetCenter.Z) * (zf - packetCenter.Z) / (2 * sigmaZSq); for (int y = 0; y < sy; y++) { float yf = (originAtLatticeCenter) ? (y - halfGridSizeY) * latticeSpacing : (y * latticeSpacing); Complex expArgZY = expArgZ + I * yf * avgMomentum.Y - (yf - packetCenter.Y) * (yf - packetCenter.Y) / (2 * sigmaYSq); float[] wfDataZY = wf.Data[z][y]; for (int x = 0; x < sx; x++) { float xf = (originAtLatticeCenter) ? (x - halfGridSizeX) * latticeSpacing : (x * latticeSpacing); Complex expArgZYX = expArgZY + I * xf * avgMomentum.X - (xf - packetCenter.X) * (xf - packetCenter.X) / (2 * sigmaXSq); Complex wfVal = norm * Complex.Exp(expArgZYX); wfDataZY[2 * x] = wfVal.Re; wfDataZY[2 * x + 1] = wfVal.Im; } } }, multiThread); wf.Normalize(); return(wf); }
/// <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 Vec3 r0 = m_initialPosition1 - m_initialPosition2; Vec3 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; int sz = 2 * m_gridSizeZ - 1; WaveFunction initialWf = WaveFunctionUtils.CreateGaussianWavePacket( new GridSpec(sx, sy, sz), 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> /// Computes a single particle probability density by integrating over one of the particle coordinates. /// </summary> private unsafe ProbabilityDensity GetSingleParticleProbability(int particleIndex, double time) { int psx = m_gridSizeX; int psy = m_gridSizeY; int psz = m_gridSizeZ; // Precompute some constants we'll need double fm1 = m_mass1 / m_totalMass; double fm2 = m_mass2 / m_totalMass; double sigmaCmFactorX = Math.Pow(m_sigmaCm.X, 4) + (time * time) / (m_totalMass * m_totalMass); double sigmaCmFactorY = Math.Pow(m_sigmaCm.Y, 4) + (time * time) / (m_totalMass * m_totalMass); double sigmaCmFactorZ = Math.Pow(m_sigmaCm.Z, 4) + (time * time) / (m_totalMass * m_totalMass); double RnormX = m_sigmaCm.X / Math.Sqrt(Math.PI * sigmaCmFactorX); double RnormY = m_sigmaCm.Y / Math.Sqrt(Math.PI * sigmaCmFactorY); double RnormZ = m_sigmaCm.Z / Math.Sqrt(Math.PI * sigmaCmFactorZ); Vec3 R0 = fm1 * m_initialPosition1 + fm2 * m_initialPosition2; Vec3 P0 = (m_initialMomentum1 + m_initialMomentum2); double RxOffset = R0.X + time * (P0.X / m_totalMass); double RyOffset = R0.Y + time * (P0.Y / m_totalMass); double RzOffset = R0.Z + time * (P0.Z / m_totalMass); double RxScale = -(m_sigmaCm.X * m_sigmaCm.X) / sigmaCmFactorX; double RyScale = -(m_sigmaCm.Y * m_sigmaCm.Y) / sigmaCmFactorY; double RzScale = -(m_sigmaCm.Z * m_sigmaCm.Z) / sigmaCmFactorZ; // Precompute the relative wavefunction probabilities ProbabilityDensity relDensity = m_visscherWf.ToRegularWavefunction().GetProbabilityDensity(); // Get a one-particle probability by marginalizing over the joint probability float[][][] oneParticleProbs = TdseUtils.Misc.Allocate3DArray(psz, psy, psx); if (particleIndex == 1) { for (int z1 = 0; z1 < psz; z1++) { // Precompute the center-of-mass wavefunction probabilities float[] ZExp = new float[psz]; for (int z2 = 0; z2 < psz; z2++) { double RzArg = (fm1 * z1 + fm2 * z2) * m_latticeSpacing - RzOffset; ZExp[z2] = (float)(RnormZ * Math.Exp(RzScale * RzArg * RzArg)); } TdseUtils.Misc.ForLoop(0, psy, y1 => { // Precompute the center-of-mass wavefunction probabilities float[] YExp = new float[psy]; for (int y2 = 0; y2 < psy; y2++) { double RyArg = (fm1 * y1 + fm2 * y2) * m_latticeSpacing - RyOffset; YExp[y2] = (float)(RnormY * Math.Exp(RyScale * RyArg * RyArg)); } for (int x1 = 0; x1 < psx; x1++) { float[] XExp = new float[psx]; for (int x2 = 0; x2 < psx; x2++) { double RxArg = (fm1 * x1 + fm2 * x2) * m_latticeSpacing - RxOffset; XExp[x2] = (float)(RnormX * Math.Exp(RxScale * RxArg * RxArg)); } fixed(float *pXExp = XExp) { float prob = 0.0f; for (int z2 = 0; z2 < psz; z2++) { int xOffset = x1 + psx - 1; float[][] relProbsZ = relDensity.Data[(z1 - z2) + psz - 1]; for (int y2 = 0; y2 < psy; y2++) { float yzExpFactor = YExp[y2] * ZExp[z2]; fixed(float *pRelProbsZY = &(relProbsZ[(y1 - y2) + psy - 1][xOffset])) { float sum = 0.0f; for (int x2 = 0; x2 < psx; x2++) { sum += pXExp[x2] * pRelProbsZY[-x2]; } prob += sum * yzExpFactor; } } } oneParticleProbs[z1][y1][x1] = prob * (m_latticeSpacing * m_latticeSpacing * m_latticeSpacing); } } }, m_multiThread); CheckForPause(); if (IsCancelled) { return(null); } } } else { for (int z2 = 0; z2 < psz; z2++) { // Precompute the center-of-mass wavefunction probabilities float[] ZExp = new float[psz]; for (int z1 = 0; z1 < psz; z1++) { double RzArg = (fm1 * z1 + fm2 * z2) * m_latticeSpacing - RzOffset; ZExp[z1] = (float)(RnormZ * Math.Exp(RzScale * RzArg * RzArg)); } TdseUtils.Misc.ForLoop(0, psy, y2 => { // Precompute the center-of-mass wavefunction probabilities float[] YExp = new float[psy]; for (int y1 = 0; y1 < psy; y1++) { double RyArg = (fm1 * y1 + fm2 * y2) * m_latticeSpacing - RyOffset; YExp[y1] = (float)(RnormY * Math.Exp(RyScale * RyArg * RyArg)); } for (int x2 = 0; x2 < psx; x2++) { float[] XExp = new float[psx]; for (int x1 = 0; x1 < psx; x1++) { double RxArg = (fm1 * x1 + fm2 * x2) * m_latticeSpacing - RxOffset; XExp[x1] = (float)(RnormX * Math.Exp(RxScale * RxArg * RxArg)); } fixed(float *pXExp = XExp) { float prob = 0.0f; for (int z1 = 0; z1 < psz; z1++) { float[][] relProbsZ = relDensity.Data[(z1 - z2) + psz - 1]; int xOffset = -x2 + psx - 1; for (int y1 = 0; y1 < psy; y1++) { float yzExpFactor = YExp[y1] * ZExp[z1]; fixed(float *pRelProbsZY = &(relProbsZ[(y1 - y2) + psy - 1][xOffset])) { float sum = 0.0f; for (int x1 = 0; x1 < psx; x1++) { sum += pXExp[x1] * pRelProbsZY[x1]; } prob += sum * yzExpFactor; } } } oneParticleProbs[z2][y2][x2] = prob * (m_latticeSpacing * m_latticeSpacing * m_latticeSpacing); } } }, m_multiThread); CheckForPause(); if (IsCancelled) { return(null); } } } return(new ProbabilityDensity(oneParticleProbs, m_visscherWf.LatticeSpacing)); }