/// <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> /// Constructor. Initializes a Visscher wavefunction from an ordinary wavefunction. /// </summary> public VisscherWf(WaveFunction inputWf, float[][][] V, float mass, float dt, bool multiThread = true) { int sx = inputWf.GridSpec.SizeX; int sy = inputWf.GridSpec.SizeY; int sz = inputWf.GridSpec.SizeZ; LatticeSpacing = inputWf.LatticeSpacing; // Allocate the arrays RealPart = TdseUtils.Misc.Allocate3DArray(sz, sy, sx); ImagPartM = TdseUtils.Misc.Allocate3DArray(sz, sy, sx); ImagPartP = TdseUtils.Misc.Allocate3DArray(sz, sy, sx); // For the real part, just copy the values from the input wavefunction. for (int z = 0; z < sz; z++) { for (int y = 0; y < sy; y++) { float[] realPartZY = RealPart[z][y]; float[] inputWfZY = inputWf.Data[z][y]; for (int x = 0; x < sx; x++) { realPartZY[x] = inputWfZY[2 * x]; } } } // For the imaginary parts, we need to compute the time evolutions. // We use a power series expansion of the time-evolution operator, accurate to 2nd order in H*dt WaveFunction H_PsiIn = inputWf.ApplyH(V, mass, multiThread); WaveFunction H2_PsiIn = H_PsiIn.ApplyH(V, mass, multiThread); float halfDt = dt / 2; float eighthDt2 = dt * dt / 8; TdseUtils.Misc.ForLoop(0, sz, (z) => { for (int y = 0; y < sy; y++) { float[] imPZY = this.ImagPartP[z][y]; float[] imMZY = this.ImagPartM[z][y]; float[] inputWfZY = inputWf.Data[z][y]; float[] H_PsiInZY = H_PsiIn.Data[z][y]; float[] H2_PsiInZY = H2_PsiIn.Data[z][y]; for (int x = 0; x < sx; x++) { int x2 = 2 * x; int x2p1 = x2 + 1; float dt0Term = inputWfZY[x2p1]; float dt1Term = halfDt * H_PsiInZY[x2]; float dt2Term = eighthDt2 * H2_PsiInZY[x2p1]; imPZY[x] = dt0Term - dt1Term - dt2Term; // [1 - i*H*(dt/2) - (1/2)H^2*(dt/2)^2] * Psi imMZY[x] = dt0Term + dt1Term - dt2Term; // [1 + i*H*(dt/2) - (1/2)H^2*(dt/2)^2] * Psi } } }, multiThread); }
/// <summary> /// Evolves the wavefunction and saves keyframes to disk. /// </summary> private void CreateAnimationFrames() { // Get a fresh output directory m_outputDir = CreateOutputDir(); // Write the run parameters to a file string paramsFile = Path.Combine(m_outputDir, "Params.txt"); File.WriteAllText(paramsFile, m_params.ToString().Replace("\n", "\r\n")); // Create the initial wavefunction WaveFunction wf = WaveFunctionUtils.CreateGaussianWavePacket( m_params.GridSpec, m_params.LatticeSpacing, m_params.ParticleMass, m_params.InitialWavePacketCenter, m_params.InitialWavePacketSize, m_params.InitialWavePacketMomentum, m_params.MultiThread ); // Save the initial wf as Frame 0 wf.SaveToVtkFile(Path.Combine(m_outputDir, "Frame_0000.vtk"), m_params.SaveFormat); m_lastSavedFrame = 0; // Create an Evolver and run it in the background Evolver.VDelegate V = (x, y, z, t, m, sx, sy, sz) => { return(m_VBuilder.V(x, y, z, t, m, sx, sy, sz)); }; m_evolver = new Evolver(wf, m_params.TotalTime, m_params.TimeStep, V, false, m_params.ParticleMass, 1, m_params.DampingBorderWidth, m_params.DampingFactor, m_params.MultiThread); m_evolver.ProgressEvent += Evolver_ProgressEvent; m_evolver.CompletionEvent += Evolver_CompletionEvent; m_evolver.RunInBackground(); }
/// <summary> /// Converts a Visscher wavefunction to a regular wavefunction. /// </summary> public WaveFunction ToRegularWavefunction(bool multiThread = true) { int sx = GridSpec.SizeX; int sy = GridSpec.SizeY; int sz = GridSpec.SizeZ; WaveFunction result = new WaveFunction(GridSpec, LatticeSpacing); TdseUtils.Misc.ForLoop(0, sz, (z) => { for (int y = 0; y < sy; y++) { float[] thisRzy = RealPart[z][y]; float[] thisIMzy = ImagPartM[z][y]; float[] thisIPzy = ImagPartP[z][y]; float[] outWfzy = result.Data[z][y]; for (int x = 0; x < sx; x++) { outWfzy[2 * x] = thisRzy[x]; // Take the square root of Im(t-dt/2) * I(t+dt/2), as this is the quantity that gives a conserved probability. float IM = thisIMzy[x]; float IP = thisIPzy[x]; float Iproduct = IM * IP; float Iout; if (Iproduct > 0.0f) { Iout = (float)Math.Sqrt(Iproduct); if (IM < 0.0f) { Iout = -Iout; } } else { Iout = 0.0f; } outWfzy[2 * x + 1] = Iout; } } }, multiThread); return(result); }
/// <summary> /// Constructor. /// </summary> public Evolver(WaveFunction initialWf, float totalTime, float timeStep, VDelegate V, bool isVTimeDependent, float particleMass, int progressReportInterval, int dampingBorderWidth = 0, float dampingFactor = 0.0f, bool multiThread = true) { m_intialWf = initialWf; m_visscherWf = null; m_potential = V; m_isTimeDependentV = isVTimeDependent; m_particleMass = particleMass; m_totalTime = totalTime; m_deltaT = timeStep; m_currentTimeStepIndex = 0; m_totalNumTimeSteps = (int)Math.Round(totalTime / timeStep) + 1; m_reportInterval = progressReportInterval; m_dampingBorderWidth = dampingBorderWidth; m_dampingFactor = dampingFactor; m_multiThread = multiThread; }
/// <summary> /// Creates a Gaussian wavepacket with given properties. /// </summary> public static WaveFunction CreateGaussianWavePacket( GridSpec gridSpec, float latticeSpacing, 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((packetWidth.X / (rootPi * sigmaXSq)) * (packetWidth.Y / (rootPi * sigmaYSq)) * (packetWidth.Z / (rootPi * sigmaZSq))); TdseUtils.Misc.ForLoop(0, sz, (z) => { float zf = 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 = y * latticeSpacing; Complex expArgZY = expArgZ + I * yf * avgMomentum.Y - (yf - packetCenter.Y) * (yf - packetCenter.Y) / (2 * sigmaYSq); float[] wfDataZY = wfData[z][y]; for (int x = 0; x < sx; x++) { float xf = 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> /// Processes a single input file. /// </summary> private void ProcessFile(string inFile, string outFile, WaveFunction.ColorDelegate colorFunc) { unsafe { int sx = -1; int sy = -1; int sz = -1; string inFormat = ""; float latticeSpacing = 0.0f; long inDataStartPos = 0; string nl = Environment.NewLine; float fa = 0.0f, fb = 0.0f; byte *fa0 = (byte *)(&fa); byte *fa1 = fa0 + 1; byte *fa2 = fa0 + 2; byte *fa3 = fa0 + 3; byte *fb0 = (byte *)(&fb); byte *fb1 = fb0 + 1; byte *fb2 = fb0 + 2; byte *fb3 = fb0 + 3; using (BinaryReader br = new BinaryReader(File.Open(inFile, FileMode.Open))) { // Parse the header of the input file while (br.BaseStream.Position < br.BaseStream.Length) { string textLine = WaveFunction.ReadTextLine(br); if (textLine.StartsWith("Wavefunction3D")) { string[] comps = textLine.Split(null); inFormat = comps[1]; latticeSpacing = Single.Parse(comps[3]); } else if (textLine.StartsWith("DIMENSIONS")) { string[] comps = textLine.Split(null); sx = Int32.Parse(comps[1]); sy = Int32.Parse(comps[2]); sz = Int32.Parse(comps[3]); } else if (textLine.StartsWith("LOOKUP_TABLE default")) { break; } } // Bail out if the header was not what we expected if (string.IsNullOrEmpty(inFormat) || (sx < 0) || (sy < 0) || (sz < 0)) { throw new ArgumentException("Invalid Wavefunction file, in Colorer.ProcessFile."); } if (inFormat != "REAL_AND_IMAG") { throw new ArgumentException("Unsupported Wavefunction format, in Colorer.ProcessFile. " + "(" + inFormat + ")"); } inDataStartPos = br.BaseStream.Position; // Create output file using (FileStream fileStream = File.Create(outFile)) { using (BinaryWriter bw = new BinaryWriter(fileStream)) { // Write the output header string outFormat = (colorFunc == null) ? "AMPLITUDE_ONLY" : "AMPLITUDE_AND_COLOR"; bw.Write(Encoding.ASCII.GetBytes("# vtk DataFile Version 3.0" + nl)); bw.Write(Encoding.ASCII.GetBytes("Wavefunction3D " + outFormat.ToString() + " " + "spacing: " + latticeSpacing.ToString() + nl)); bw.Write(Encoding.ASCII.GetBytes("BINARY" + nl)); bw.Write(Encoding.ASCII.GetBytes("DATASET STRUCTURED_POINTS" + nl)); bw.Write(Encoding.ASCII.GetBytes("DIMENSIONS " + sx + " " + sy + " " + sz + nl)); bw.Write(Encoding.ASCII.GetBytes("ORIGIN 0 0 0" + nl)); bw.Write(Encoding.ASCII.GetBytes("SPACING 1 1 1" + nl)); bw.Write(Encoding.ASCII.GetBytes("POINT_DATA " + sx * sy * sz + nl)); bw.Write(Encoding.ASCII.GetBytes("SCALARS amplitude float" + nl)); bw.Write(Encoding.ASCII.GetBytes("LOOKUP_TABLE default" + nl)); // Read {re,im} pairs from the input file, and write the corresponding ampl values to the output file // (Avoid reading-in the whole input file up-front, as it may be extremely large.) byte[] outPlane = new byte[sx * sy * 4]; float maxAmpl = 0.0f; for (int z = 0; z < sz; z++) { byte[] inPlane = br.ReadBytes(sx * sy * 8); int ni = 0, no = 0;; for (int y = 0; y < sy; y++) { for (int x = 0; x < sx; x++) { *fa3 = inPlane[ni]; // Reverse the byte order *fa2 = inPlane[ni + 1]; *fa1 = inPlane[ni + 2]; *fa0 = inPlane[ni + 3]; *fb3 = inPlane[ni + 4]; *fb2 = inPlane[ni + 5]; *fb1 = inPlane[ni + 6]; *fb0 = inPlane[ni + 7]; ni += 8; fa = (float)Math.Sqrt(fa * fa + fb * fb); if (fa > maxAmpl) { maxAmpl = fa; } outPlane[no] = *fa3; outPlane[no + 1] = *fa2; outPlane[no + 2] = *fa1; outPlane[no + 3] = *fa0; no += 4; } } bw.Write(outPlane); } // Now write the colors if (colorFunc != null) { bw.Write(Encoding.ASCII.GetBytes("SCALARS colors unsigned_char 3" + nl)); bw.Write(Encoding.ASCII.GetBytes("LOOKUP_TABLE default" + nl)); br.BaseStream.Seek(inDataStartPos, SeekOrigin.Begin); byte[] colorPlane = new byte[sx * sy * 3]; for (int z = 0; z < sz; z++) { byte[] inPlane = br.ReadBytes(sx * sy * 8); int ni = 0, no = 0;; for (int y = 0; y < sy; y++) { for (int x = 0; x < sx; x++) { *fa3 = inPlane[ni]; // Real part *fa2 = inPlane[ni + 1]; *fa1 = inPlane[ni + 2]; *fa0 = inPlane[ni + 3]; *fb3 = inPlane[ni + 4]; // Imaginary part *fb2 = inPlane[ni + 5]; *fb1 = inPlane[ni + 6]; *fb0 = inPlane[ni + 7]; ni += 8; Color color = (colorFunc == null) ? Color.Blue : colorFunc(fb, fa, maxAmpl); colorPlane[no] = color.R; colorPlane[no + 1] = color.G; colorPlane[no + 2] = color.B; no += 3; } } bw.Write(colorPlane); } } } } } } }
/// <summary> /// Processes a single input file. /// </summary> private void ProcessFile(string inFile, string outFile) { unsafe { int sx = -1, sy = -1, sz = -1; string format = ""; float latticeSpacing = 0.0f; string nl = Environment.NewLine; using (BinaryReader br = new BinaryReader(File.Open(inFile, FileMode.Open))) { // Parse the header of the input file while (br.BaseStream.Position < br.BaseStream.Length) { string textLine = WaveFunction.ReadTextLine(br); if (textLine.StartsWith("Wavefunction3D")) { string[] comps = textLine.Split(null); format = comps[1]; latticeSpacing = (float)(Single.Parse(comps[3]) / m_upsampFactor); } else if (textLine.StartsWith("DIMENSIONS")) { string[] comps = textLine.Split(null); sx = Int32.Parse(comps[1]); sy = Int32.Parse(comps[2]); sz = Int32.Parse(comps[3]); } else if (textLine.StartsWith("LOOKUP_TABLE default")) { break; } } // Bail out if the header was not what we expected if (string.IsNullOrEmpty(format) || (sx < 0) || (sy < 0) || (sz < 0)) { throw new ArgumentException("Invalid Wavefunction file, in Colorer.ProcessFile."); } if (format != "REAL_AND_IMAG") { throw new ArgumentException("Unsupported Wavefunction format, in Smoother.ProcessFile. " + "(" + format + ")"); } // Allocate some storage int sxu = (int)Math.Max(1, sx * m_upsampFactor); int syu = (int)Math.Max(1, sy * m_upsampFactor); int szu = (int)Math.Max(1, sz * m_upsampFactor); int sxu2 = 2 * sxu; float[][] workSpace = TdseUtils.Misc.Allocate2DArray(sy, 2 * sx); float[][] outPlane = TdseUtils.Misc.Allocate2DArray(syu, sxu2); // Read the initial few xy planes float[][][] iXYPlanes = new float[sz][][]; for (int zIn = 0; zIn < 4; zIn++) { iXYPlanes[zIn] = TdseUtils.Misc.Allocate2DArray(syu, sxu2); GetNextXYPlane(br, iXYPlanes[zIn], workSpace, m_upsampFactor); } // Precalculate the z-weights and indices int[] zInm2, zInm1, zInp1, zInp2; float[] wzm2, wzm1, wzp1, wzp2; GetUpsampleArrays(sz, m_upsampFactor, out zInm2, out zInm1, out zInp1, out zInp2, out wzm2, out wzm1, out wzp1, out wzp2); // Create and open the output file using (FileStream fileStream = File.Create(outFile)) { using (BinaryWriter bw = new BinaryWriter(fileStream)) { // Write the output header bw.Write(Encoding.ASCII.GetBytes("# vtk DataFile Version 3.0" + nl)); bw.Write(Encoding.ASCII.GetBytes("Wavefunction3D " + "REAL_AND_IMAG" + " " + "spacing: " + latticeSpacing.ToString() + nl)); bw.Write(Encoding.ASCII.GetBytes("BINARY" + nl)); bw.Write(Encoding.ASCII.GetBytes("DATASET STRUCTURED_POINTS" + nl)); bw.Write(Encoding.ASCII.GetBytes("DIMENSIONS " + sxu + " " + syu + " " + szu + nl)); bw.Write(Encoding.ASCII.GetBytes("ORIGIN 0 0 0" + nl)); bw.Write(Encoding.ASCII.GetBytes("SPACING 1 1 1" + nl)); bw.Write(Encoding.ASCII.GetBytes("POINT_DATA " + sxu * syu * szu + nl)); bw.Write(Encoding.ASCII.GetBytes("SCALARS wf float 2" + nl)); bw.Write(Encoding.ASCII.GetBytes("LOOKUP_TABLE default" + nl)); // Loop over the output z-planes for (int zOut = 0; zOut < szu; zOut++) { // Cache z-weights and offsets float Wzm2 = wzm2[zOut]; float Wzm1 = wzm1[zOut]; float Wzp1 = wzp1[zOut]; float Wzp2 = wzp2[zOut]; float[][] pixValsZInm2 = iXYPlanes[zInm2[zOut]]; float[][] pixValsZInm1 = iXYPlanes[zInm1[zOut]]; float[][] pixValsZInp1 = iXYPlanes[zInp1[zOut]]; float[][] pixValsZInp2 = iXYPlanes[zInp2[zOut]]; if (pixValsZInp2 == null) { // Load (and upsample) the next xy plane float[][] temp = iXYPlanes[zInp2[zOut] - 4]; iXYPlanes[zInp2[zOut] - 4] = null; GetNextXYPlane(br, temp, workSpace, m_upsampFactor); pixValsZInp2 = iXYPlanes[zInp2[zOut]] = temp; } for (int yOut = 0; yOut < syu; yOut++) { float[] pixValsZInm2Y = pixValsZInm2[yOut]; float[] pixValsZInm1Y = pixValsZInm1[yOut]; float[] pixValsZInp1Y = pixValsZInp1[yOut]; float[] pixValsZInp2Y = pixValsZInp2[yOut]; float[] outPlaneY = outPlane[yOut]; for (int xOut = 0; xOut < sxu2; xOut++) { outPlaneY[xOut] = Wzm2 * pixValsZInm2Y[xOut] + Wzm1 * pixValsZInm1Y[xOut] + Wzp1 * pixValsZInp1Y[xOut] + Wzp2 * pixValsZInp2Y[xOut]; } } WriteXYPlane(bw, outPlane); } } } } } }
/// <summary> /// Processes a single input file. /// </summary> private void ProcessFile(string inFile, string outFile) { unsafe { int sx = -1, sy = -1, sz = -1; string format = ""; float latticeSpacing = 0.0f; string nl = Environment.NewLine; float[] kernel = CreateGaussianKernel(m_smoothingFactor); int sk = kernel.Length; int hsk = (sk - 1) / 2; using (BinaryReader br = new BinaryReader(File.Open(inFile, FileMode.Open))) { // Parse the header of the input file while (br.BaseStream.Position < br.BaseStream.Length) { string textLine = WaveFunction.ReadTextLine(br); if (textLine.StartsWith("Wavefunction3D")) { string[] comps = textLine.Split(null); format = comps[1]; latticeSpacing = Single.Parse(comps[3]); } else if (textLine.StartsWith("DIMENSIONS")) { string[] comps = textLine.Split(null); sx = Int32.Parse(comps[1]); sy = Int32.Parse(comps[2]); sz = Int32.Parse(comps[3]); } else if (textLine.StartsWith("LOOKUP_TABLE default")) { break; } } // Bail out if the header was not what we expected if (string.IsNullOrEmpty(format) || (sx < 0) || (sy < 0) || (sz < 0)) { throw new ArgumentException("Invalid Wavefunction file, in Colorer.ProcessFile."); } if (format != "REAL_AND_IMAG") { throw new ArgumentException("Unsupported Wavefunction format, in Smoother.ProcessFile. " + "(" + format + ")"); } // Allocate some storage float[][][] slab = TdseUtils.Misc.Allocate3DArray(sk, sy, 2 * sx); float[][] outPlane = TdseUtils.Misc.Allocate2DArray(sy, 2 * sx); float[][] workSpace = TdseUtils.Misc.Allocate2DArray(sy, 2 * sx); // Create and open the output file using (FileStream fileStream = File.Create(outFile)) { using (BinaryWriter bw = new BinaryWriter(fileStream)) { // Write the output header bw.Write(Encoding.ASCII.GetBytes("# vtk DataFile Version 3.0" + nl)); bw.Write(Encoding.ASCII.GetBytes("Wavefunction3D " + "REAL_AND_IMAG" + " " + "spacing: " + latticeSpacing.ToString() + nl)); bw.Write(Encoding.ASCII.GetBytes("BINARY" + nl)); bw.Write(Encoding.ASCII.GetBytes("DATASET STRUCTURED_POINTS" + nl)); bw.Write(Encoding.ASCII.GetBytes("DIMENSIONS " + sx + " " + sy + " " + sz + nl)); bw.Write(Encoding.ASCII.GetBytes("ORIGIN 0 0 0" + nl)); bw.Write(Encoding.ASCII.GetBytes("SPACING 1 1 1" + nl)); bw.Write(Encoding.ASCII.GetBytes("POINT_DATA " + sx * sy * sz + nl)); bw.Write(Encoding.ASCII.GetBytes("SCALARS wf float 2" + nl)); bw.Write(Encoding.ASCII.GetBytes("LOOKUP_TABLE default" + nl)); // Read the initial few planes for (int i = hsk; i < sk; i++) { GetNextXYPlane(br, kernel, workSpace, slab[i]); } for (int i = 0; i < hsk; i++) { TdseUtils.Misc.Copy2DArray(slab[sk - 1 - i], slab[i]); // Mirror boundary conditions on z } // Smooth along z, and write-out the result SmoothAlongZ(slab, kernel, outPlane); WriteXYPlane(bw, outPlane); // Loop over remaining planes for (int z = 1; z < sz; z++) { // Cycle the z-planes, and read-in a new one float[][] temp = slab[0]; for (int i = 0; i < sk - 1; i++) { slab[i] = slab[i + 1]; } slab[sk - 1] = temp; if (z < sz - hsk) { GetNextXYPlane(br, kernel, workSpace, slab[sk - 1]); } else { TdseUtils.Misc.Copy2DArray(slab[2 * (sz - 1 - z)], slab[sk - 1]); // Mirror boundary conditions on z } // Smooth along z, and write-out the result SmoothAlongZ(slab, kernel, outPlane); WriteXYPlane(bw, outPlane); } } } } } }
/// <summary> /// Processes a single input file. /// </summary> private void ProcessFile(string inFile, string outFile) { unsafe { int sxIn = -1, syIn = -1, szIn = -1; int sxOut = -1, syOut = -1, szOut = -1; string format = ""; float latticeSpacing = 0.0f; string nl = Environment.NewLine; using (BinaryReader br = new BinaryReader(File.Open(inFile, FileMode.Open))) { // Parse the header of the input file while (br.BaseStream.Position < br.BaseStream.Length) { string textLine = WaveFunction.ReadTextLine(br); if (textLine.StartsWith("Wavefunction3D")) { string[] comps = textLine.Split(null); format = comps[1]; latticeSpacing = Single.Parse(comps[3]); } else if (textLine.StartsWith("DIMENSIONS")) { string[] comps = textLine.Split(null); sxIn = Int32.Parse(comps[1]); syIn = Int32.Parse(comps[2]); szIn = Int32.Parse(comps[3]); } else if (textLine.StartsWith("LOOKUP_TABLE default")) { break; } } // Bail out if the header was not what we expected if (string.IsNullOrEmpty(format) || (sxIn < 0) || (syIn < 0) || (szIn < 0)) { throw new ArgumentException("Invalid Wavefunction file, in Cropper.ProcessFile."); } // Create output file sxOut = sxIn - m_xCrop1 - m_xCrop2; syOut = syIn - m_yCrop1 - m_yCrop2; szOut = szIn - m_zCrop1 - m_zCrop2; using (FileStream fileStream = File.Create(outFile)) { using (BinaryWriter bw = new BinaryWriter(fileStream)) { // Write the output header bw.Write(Encoding.ASCII.GetBytes("# vtk DataFile Version 3.0" + nl)); bw.Write(Encoding.ASCII.GetBytes("Wavefunction3D " + format.ToString() + " " + "spacing: " + latticeSpacing.ToString() + nl)); bw.Write(Encoding.ASCII.GetBytes("BINARY" + nl)); bw.Write(Encoding.ASCII.GetBytes("DATASET STRUCTURED_POINTS" + nl)); bw.Write(Encoding.ASCII.GetBytes("DIMENSIONS " + sxOut + " " + syOut + " " + szOut + nl)); bw.Write(Encoding.ASCII.GetBytes("ORIGIN 0 0 0" + nl)); bw.Write(Encoding.ASCII.GetBytes("SPACING 1 1 1" + nl)); bw.Write(Encoding.ASCII.GetBytes("POINT_DATA " + sxOut * syOut * szOut + nl)); // Read values from the input file, and write (some of) them to the output file. // (Avoid reading-in the whole input file up-front, as it may be extremely large.) if (format == "REAL_AND_IMAG") { bw.Write(Encoding.ASCII.GetBytes("SCALARS wf float 2" + nl)); bw.Write(Encoding.ASCII.GetBytes("LOOKUP_TABLE default" + nl)); byte[] outPlane = new byte[sxOut * syOut * 8]; for (int z = 0; z < szIn - m_zCrop2; z++) { byte[] inPlane = br.ReadBytes(sxIn * syIn * 8); if (z < m_zCrop1) { continue; } for (int y = m_yCrop1; y < syIn - m_yCrop2; y++) { Buffer.BlockCopy(inPlane, (y * sxIn + m_xCrop1) * 8, outPlane, (y - m_yCrop1) * sxOut * 8, sxOut * 8); } bw.Write(outPlane); } } else if ((format == "AMPLITUDE_ONLY") || (format == "AMPLITUDE_AND_COLOR")) { bw.Write(Encoding.ASCII.GetBytes("SCALARS amplitude float" + nl)); bw.Write(Encoding.ASCII.GetBytes("LOOKUP_TABLE default" + nl)); byte[] outPlane = new byte[sxOut * syOut * 4]; for (int z = 0; z < szIn; z++) { byte[] inPlane = br.ReadBytes(sxIn * syIn * 4); if ((z < m_zCrop1) || (z > szIn - m_zCrop2 - 1)) { continue; } for (int y = m_yCrop1; y < syIn - m_yCrop2; y++) { Buffer.BlockCopy(inPlane, (y * sxIn + m_xCrop1) * 4, outPlane, (y - m_yCrop1) * sxOut * 4, sxOut * 4); } bw.Write(outPlane); } if (format == "AMPLITUDE_AND_COLOR") { bw.Write(Encoding.ASCII.GetBytes("SCALARS colors unsigned_char 3" + nl)); bw.Write(Encoding.ASCII.GetBytes("LOOKUP_TABLE default" + nl)); outPlane = new byte[sxOut * syOut * 3]; for (int z = 0; z < szIn - m_zCrop2; z++) { byte[] inPlane = br.ReadBytes(sxIn * syIn * 3); if (z < m_zCrop1) { continue; } for (int y = m_yCrop1; y < syIn - m_yCrop2; y++) { Buffer.BlockCopy(inPlane, (y * sxIn + m_xCrop1) * 3, outPlane, (y - m_yCrop1) * sxOut * 3, sxOut * 3); } bw.Write(outPlane); } } } else { throw new ArgumentException("Unsupported Wavefunction format, in Cropper.ProcessFile. " + "(" + format + ")"); } } } } } }
/// <summary> /// Computes the result of applying a given Hamiltonian operator to this wavefunction. /// </summary> public WaveFunction ApplyH(float[][][] V, float mass, bool multiThread = true) { // Initialize locals int sx = GridSpec.SizeX; int sy = GridSpec.SizeY; int sz = GridSpec.SizeZ; int sx2 = 2 * sx; int sx2m2 = sx2 - 2; int sym1 = sy - 1; int szm1 = sz - 1; float keFactor = (1.0f / 12.0f) / (2 * mass * m_latticeSpacing * m_latticeSpacing); WaveFunction outWf = new WaveFunction(GridSpec, m_latticeSpacing); // Compute H * Wf TdseUtils.Misc.ForLoop(0, sz, (z) => { int zp = (z < szm1) ? z + 1 : 0; int zpp = (zp < szm1) ? zp + 1 : 0; int zm = (z > 0) ? z - 1 : szm1; int zmm = (zm > 0) ? zm - 1 : szm1; for (int y = 0; y < 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[] inWf_z_y = m_data[z][y]; float[] inWf_z_ym = m_data[z][ym]; float[] inWf_z_yp = m_data[z][yp]; float[] inWf_z_ymm = m_data[z][ymm]; float[] inWf_z_ypp = m_data[z][ypp]; float[] inWf_zm_y = m_data[zm][y]; float[] inWf_zp_y = m_data[zp][y]; float[] inWf_zmm_y = m_data[zmm][y]; float[] inWf_zpp_y = m_data[zpp][y]; float[] outWf_z_y = outWf.m_data[z][y]; float[] V_z_y = V[z][y]; for (int rx = 0; rx < sx2; rx += 2) { int rxp = (rx < sx2m2) ? rx + 2 : 0; int rxpp = (rxp < sx2m2) ? rxp + 2 : 0; int rxm = (rx > 0) ? rx - 2 : sx2m2; int rxmm = (rxm > 0) ? rxm - 2 : sx2m2; int x = rx / 2; // Kinetic energy terms. float kR = keFactor * ( 90.0f * inWf_z_y[rx] - 16.0f * (inWf_zm_y[rx] + inWf_zp_y[rx] + inWf_z_yp[rx] + inWf_z_ym[rx] + inWf_z_y[rxm] + inWf_z_y[rxp]) + (inWf_zmm_y[rx] + inWf_zpp_y[rx] + inWf_z_ypp[rx] + inWf_z_ymm[rx] + inWf_z_y[rxmm] + inWf_z_y[rxpp]) ); int ix = rx + 1; float kI = keFactor * ( 90.0f * inWf_z_y[ix] - 16.0f * (inWf_zm_y[ix] + inWf_zp_y[ix] + inWf_z_yp[ix] + inWf_z_ym[ix] + inWf_z_y[rxm + 1] + inWf_z_y[rxp + 1]) + (inWf_zmm_y[ix] + inWf_zpp_y[ix] + inWf_z_ypp[ix] + inWf_z_ymm[ix] + inWf_z_y[rxmm + 1] + inWf_z_y[rxpp + 1]) ); // Potential energy terms float vR = V_z_y[x] * inWf_z_y[rx]; float vI = V_z_y[x] * inWf_z_y[ix]; outWf_z_y[rx] = kR + vR; outWf_z_y[ix] = kI + vI; } } }, multiThread); return(outWf); }