/// <summary> /// Reads density values from a vtk stream. /// </summary> private static ProbabilityDensity FromVtkStream(BinaryReader br, int sizeX, int sizeY, int sizeZ, float latticeSpacing) { ProbabilityDensity result = new ProbabilityDensity(new GridSpec(sizeX, sizeY, sizeZ), latticeSpacing); unsafe { // For performance, we keep a temporary float value with pointers to its bytes float floatVal = 0.0f; byte *floatBytes0 = (byte *)(&floatVal); byte *floatBytes1 = floatBytes0 + 1; byte *floatBytes2 = floatBytes0 + 2; byte *floatBytes3 = floatBytes0 + 3; // Read the density values ReadTextLine(br); ReadTextLine(br); for (int z = 0; z < sizeZ; z++) { byte[] bytePlane = br.ReadBytes(sizeX * sizeY * 4); int n = 0; for (int y = 0; y < sizeY; y++) { float[] dataZY = result.Data[z][y]; for (int x = 0; x < sizeX; x++) { *floatBytes3 = bytePlane[n]; *floatBytes2 = bytePlane[n + 1]; *floatBytes1 = bytePlane[n + 2]; *floatBytes0 = bytePlane[n + 3]; dataZY[x] = floatVal; n += 4; } } } } return(result); }
/// <summary> /// Saves the current probability densities to a vtk file. /// </summary> private void SaveOutputFile(string fileSpec) { float time = m_currentTimeStepIndex * m_deltaT; ProbabilityDensity prob1 = GetSingleParticleProbability(1, time); if (prob1 == null) { return; } System.Diagnostics.Trace.WriteLine(prob1.Norm().ToString()); ProbabilityDensity prob2 = GetSingleParticleProbability(2, time); if (prob2 == null) { return; } System.Diagnostics.Trace.WriteLine(" " + prob2.Norm().ToString()); ProbabilityDensity.SaveToVtkFile(new ProbabilityDensity[] { prob1, prob2 }, fileSpec); }
/// <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)); }