/// <summary>
        /// Computes the intergrated probability density.
        /// </summary>
        public float Norm()
        {
            GridSpec gridSpec = GridSpec;
            int      sx       = gridSpec.SizeX;
            int      sy       = gridSpec.SizeY;
            int      sz       = gridSpec.SizeZ;

            float[] norm = new float[sz];

            TdseUtils.Misc.ForLoop(0, sz, z =>
            {
                float xySum = 0.0f;
                for (int y = 0; y < sy; y++)
                {
                    float[] dataZY = m_data[z][y];

                    for (int x = 0; x < sx; x++)
                    {
                        xySum += dataZY[x];
                    }
                }
                norm[z] = xySum;
            }, true);

            float normTot = 0.0f;

            for (int z = 0; z < sz; z++)
            {
                normTot += norm[z];
            }
            normTot *= (m_latticeSpacing * m_latticeSpacing * m_latticeSpacing);
            return(normTot);
        }
        /// <summary>
        /// Writes a set of densities to a file, in VTK format.
        /// </summary>
        public static void SaveToVtkFile(ProbabilityDensity[] probs, string fileSpec)
        {
            using (FileStream fileStream = File.Create(fileSpec))
            {
                using (BinaryWriter bw = new BinaryWriter(fileStream))
                {
                    GridSpec gridSpec = probs[0].GridSpec;
                    int      sx       = gridSpec.SizeX;
                    int      sy       = gridSpec.SizeY;
                    int      sz       = gridSpec.SizeZ;
                    string   nl       = Environment.NewLine;

                    // Write the header
                    bw.Write(Encoding.ASCII.GetBytes("# vtk DataFile Version 3.0" + nl));
                    bw.Write(Encoding.ASCII.GetBytes("Probability3D2P " + "spacing: " + probs[0].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));

                    for (int i = 0; i < probs.Length; i++)
                    {
                        probs[i].ToVtkStream(bw, "prob_" + i.ToString());
                    }
                }
            }
        }
        /// <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>
        /// Writes the density values to a stream, in vtk format.
        /// </summary>
        private void ToVtkStream(BinaryWriter bw, string name)
        {
            GridSpec gridSpec = GridSpec;
            int      sx       = gridSpec.SizeX;
            int      sy       = gridSpec.SizeY;
            int      sz       = gridSpec.SizeZ;
            string   nl       = Environment.NewLine;

            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;

                bw.Write(Encoding.ASCII.GetBytes("SCALARS " + name + " float" + nl));
                bw.Write(Encoding.ASCII.GetBytes("LOOKUP_TABLE default" + nl));

                byte[] bytePlane = new byte[sx * sy * 4];
                for (int z = 0; z < sz; z++)
                {
                    int n = 0;
                    for (int y = 0; y < sy; y++)
                    {
                        float[] dataZY = m_data[z][y];

                        for (int x = 0; x < sx; x++)
                        {
                            floatVal = dataZY[x];

                            bytePlane[n]     = *floatBytes3; // Reverse the bytes, since VTK wants big-endian data
                            bytePlane[n + 1] = *floatBytes2;
                            bytePlane[n + 2] = *floatBytes1;
                            bytePlane[n + 3] = *floatBytes0;
                            n += 4;
                        }
                    }
                    bw.Write(bytePlane);
                }
            }
        }
Exemple #5
0
 /// <summary>
 /// Constructor.
 /// </summary>
 public WaveFunction(GridSpec gridSpec, float latticeSpacing)
 {
     m_data           = TdseUtils.Misc.Allocate3DArray(gridSpec.SizeZ, gridSpec.SizeY, 2 * gridSpec.SizeX);
     m_latticeSpacing = latticeSpacing;
 }
 /// <summary>
 /// Constructor.
 /// </summary>
 public ProbabilityDensity(GridSpec gridSpec, float latticeSpacing)
 {
     m_data           = TdseUtils.Misc.Allocate3DArray(gridSpec.SizeZ, gridSpec.SizeY, gridSpec.SizeX);
     m_latticeSpacing = latticeSpacing;
 }
Exemple #7
0
 /// <summary>
 /// Compares two GridSpecs by value.
 /// </summary>
 public bool ValueEquals(GridSpec that)
 {
     return((this.SizeX == that.SizeX) && (this.SizeY == that.SizeY) && (this.SizeZ == that.SizeZ));
 }
Exemple #8
0
 /// <summary>
 /// Copy constructor.
 /// </summary>
 public GridSpec(GridSpec src)
 {
     SizeX = src.SizeX;
     SizeY = src.SizeY;
     SizeZ = src.SizeZ;
 }
Exemple #9
0
        /// <summary>
        /// Evolves the wavefunction by a single time step
        /// </summary>
        private void EvolveByOneTimeStep(VisscherWf wf, float[][][] V)
        {
            GridSpec wfGrid = wf.GridSpec;
            int      sx     = wfGrid.SizeX;
            int      sy     = wfGrid.SizeY;
            int      sz     = wfGrid.SizeZ;
            int      sxm1   = sx - 1;
            int      sym1   = sy - 1;
            int      szm1   = sz - 1;

            float keFactor = (1.0f / 12.0f) / (2 * m_reducedMass * wf.LatticeSpacing * wf.LatticeSpacing);


            // Compute the next real part in terms of the current imaginary part
            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[] V_z_y     = V[z][y];
                    float[] wfR_z_y   = wf.RealPart[z][y];
                    float[] wfI_z_y   = wf.ImagPartP[z][y];
                    float[] wfI_z_ym  = wf.ImagPartP[z][ym];
                    float[] wfI_z_yp  = wf.ImagPartP[z][yp];
                    float[] wfI_z_ymm = wf.ImagPartP[z][ymm];
                    float[] wfI_z_ypp = wf.ImagPartP[z][ypp];
                    float[] wfI_zm_y  = wf.ImagPartP[zm][y];
                    float[] wfI_zp_y  = wf.ImagPartP[zp][y];
                    float[] wfI_zmm_y = wf.ImagPartP[zmm][y];
                    float[] wfI_zpp_y = wf.ImagPartP[zpp][y];

                    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;

                        // Discretization of the 2nd derivative
                        float ke = keFactor * (
                            90.0f * wfI_z_y[x] -
                            16.0f * (wfI_zm_y[x] + wfI_zp_y[x] + wfI_z_yp[x] + wfI_z_ym[x] + wfI_z_y[xm] + wfI_z_y[xp]) +
                            (wfI_zmm_y[x] + wfI_zpp_y[x] + wfI_z_ypp[x] + wfI_z_ymm[x] + wfI_z_y[xmm] + wfI_z_y[xpp])
                            );

                        float pe = V_z_y[x] * wfI_z_y[x];

                        wfR_z_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, 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[] V_z_y     = V[z][y];
                    float[] wfIM_z_y  = wf.ImagPartM[z][y];
                    float[] wfIP_z_y  = wf.ImagPartP[z][y];
                    float[] wfR_z_y   = wf.RealPart[z][y];
                    float[] wfR_z_ym  = wf.RealPart[z][ym];
                    float[] wfR_z_yp  = wf.RealPart[z][yp];
                    float[] wfR_z_ymm = wf.RealPart[z][ymm];
                    float[] wfR_z_ypp = wf.RealPart[z][ypp];
                    float[] wfR_zm_y  = wf.RealPart[zm][y];
                    float[] wfR_zp_y  = wf.RealPart[zp][y];
                    float[] wfR_zmm_y = wf.RealPart[zmm][y];
                    float[] wfR_zpp_y = wf.RealPart[zpp][y];

                    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;

                        // Discretization of the 2nd derivative
                        float ke = keFactor * (
                            90.0f * wfR_z_y[x] -
                            16.0f * (wfR_zm_y[x] + wfR_zp_y[x] + wfR_z_yp[x] + wfR_z_ym[x] + wfR_z_y[xm] + wfR_z_y[xp]) +
                            (wfR_zmm_y[x] + wfR_zpp_y[x] + wfR_z_ypp[x] + wfR_z_ymm[x] + wfR_z_y[xmm] + wfR_z_y[xpp])
                            );

                        float pe = V_z_y[x] * wfR_z_y[x];

                        wfIP_z_y[x] = wfIM_z_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);
            }
        }