/// <summary> /// Computes psi_k=psi_k*exp(-0.5*dt*1i*(hbar/m)*kˆ2). /// </summary> public void addPhaseMomentum() { for (int i = 0; i < psi.Length; i++) { psi[i] = psi[i] * ComplexNumber.Exp(-0.5 * ComplexNumber.ImaginaryOne * deltaT * PhysConst.hbar / mass * Math.Pow(K[i], 2)); } }
/// <summary> /// Computes psi=psi.*exp(-0.5*1i*dt*(V+(g1d/hbar)*abs(psi).ˆ2)). /// </summary> public void addPhaseSpatial() { for (int i = 0; i < psi.Length; i++) { psi[i] = psi[i] * ComplexNumber.Exp(-0.5 * ComplexNumber.ImaginaryOne * deltaT * (V[i] + g1D / PhysConst.hbar * Math.Pow(psi[i].Norm(), 2))); } }
/// <summary> /// The DFT calculates the discret Fourier transform of a complex array /// </summary> /// <returns>An array which is Fourier transformed</returns> /// <param name="f">Array to be Fourier transformed</param> public static ComplexNumber[] DFT(ComplexNumber[] f) { int N = f.Length; ComplexNumber[] F = new ComplexNumber[N]; for (int j = 0; j < N; j++) { for (int i = 0; i < N; i++) { F[j] += ComplexNumber.Exp(-ComplexNumber.ImaginaryOne * 2 * Math.PI * j * i / N) * f[i]; } } return(F); }
/// <summary> /// CT performs a FFT using the Cooley-Tukey algorithm, which requires an array of the power of two. /// The algorithm is recursively. /// </summary> /// <returns>Fourier transformed array</returns> /// <param name="f">Array to be Fourier transformed</param> public static ComplexNumber[] CT(ComplexNumber[] f) { int N = f.Length; ComplexNumber[] F = new ComplexNumber[N]; if (N < 2) { F = f; // breaks the recursion at its smallest array size of 1 } else { // Creates to halfsize arrays for even and odd indices ComplexNumber[] even = new ComplexNumber[N / 2]; ComplexNumber[] odd = new ComplexNumber[N / 2]; for (int i = 0; i < N / 2; i++) { even[i] = f[2 * i]; odd[i] = f[2 * i + 1]; } // prepares arrays, in which the Fouriertrans formed version will be saved ComplexNumber[] EVEN = new ComplexNumber[N / 2]; ComplexNumber[] ODD = new ComplexNumber[N / 2]; // Fourier transforms the smaller arrays by calling the function itself EVEN = CT(even); ODD = CT(odd); // reassambles the values in the correct order for (int i = 0; i < N / 2; i++) { F[i] = EVEN[i] + ComplexNumber.Exp(-ComplexNumber.ImaginaryOne * 2 * Math.PI / N * i) * ODD[i]; F[i + N / 2] = EVEN[i] - ComplexNumber.Exp(-ComplexNumber.ImaginaryOne * 2 * Math.PI / N * i) * ODD[i]; } } // returns the Fourier transformed array return(F); }
/// <summary> /// Simulates on timestep of the time evolution by performing the splitstep fourier method only once. /// </summary> /// <param name="FT">Algorithm which will be used for the Fouriertransformation</param> public void splitStepFourier(string FT) { int size = this.psi.Length; // psi=psi.*exp(-0.5*1i*dt*(V+(g1d/hbar)*abs(psi).ˆ2)); for (int i = 0; i < size; i++) { psi[i] = psi[i] * ComplexNumber.Exp(-0.5 * ComplexNumber.ImaginaryOne * deltaT * (V[i] + g1D / PhysConst.hbar * Math.Pow(psi[i].Norm(), 2))); } // decides which algorithm will be used for the FT switch (FT) { case "DFT": psi = FFT.DFT(psi); break; case "CT": psi = FFT.CT(psi); break; case "BR": psi = FFT.BR(psi, reversedBits); break; default: break; } psi = FFT.Shift(psi); // shift the lower half with the upper one to restore normal order for (int i = 0; i < size; i++) { psi[i] = psi[i] / size; } // psi_k=psi_k*exp(-0.5*dt*1i*(hbar/m)*kˆ2) for (int i = 0; i < size; i++) { psi[i] = psi[i] * ComplexNumber.Exp(-0.5 * ComplexNumber.ImaginaryOne * deltaT * PhysConst.hbar / mass * Math.Pow(K[i], 2)); } psi = FFT.Shift(psi); // shifts again, so that the result of the IFT will be normal orderd // decides which algorithm will be used for the IFT switch (FT) { case "DFT": psi = FFT.IDFT(psi); break; case "CT": psi = FFT.ICT(psi); break; case "BR": psi = FFT.IBR(psi, reversedBits); break; default: break; } for (int i = 0; i < size; i++) { psi[i] = psi[i] * size; } //psi = psi.* exp(-0.5 * 1i * dt * (V + (g1d / hbar) * abs(psi).ˆ2)); for (int i = 0; i < size; i++) { psi[i] = psi[i] * ComplexNumber.Exp(-0.5 * ComplexNumber.ImaginaryOne * deltaT * (V[i] + g1D / PhysConst.hbar * Math.Pow(psi[i].Norm(), 2))); } }
/// <summary> /// Transformation algorithm to perform a FFT using the Bit reversal structure. /// </summary> /// <remarks> /// The FT is performed by setting the <c>negativeTwidleFactor</c> to <c>true</c>, its inverse by setting it to <c>false</c>. /// </remarks> /// <returns>Transformed array</returns> /// <param name="negativeTwidleFactor">If set to <c>true</c> FT is performed, if <c>false</c> its inverse.</param> /// <param name="f">Array to be transformed</param> /// <param name="reversedBits">Reversed bit array, needs to be precalculated by <c>BitReverse</c></param> public static ComplexNumber[] Transform(bool negativeTwidleFactor, ComplexNumber[] f, uint[] reversedBits) { ComplexNumber[] workF = (ComplexNumber[])f.Clone(); int size = f.Length; if (size != reversedBits.Length) { throw new Exception("The arrays dont have the same lenght"); } int a = 0; int findA = size; while (findA > 1) { findA = findA >> 1; a++; } // sets the prefactor for the twiddle factor to perform either FFT or IFFT int preFactor; if (negativeTwidleFactor) { preFactor = -1; } else { preFactor = 1; } // prepare necassary variables ComplexNumber even, odd, wM, w; int shift, m; //orders the array according to the bit reversal for (int i = 0; i < f.Length; i++) { workF[i] = f[reversedBits[i]]; } // three for loops to process the full FFT/IFFT // the result of the loops gives the FFT/IFFT in the normal ordered form for (int s = 1; s <= a; s++) { shift = 1 << (s - 1); // = 2^(s-1) via bitshift m = 1 << s; // = 2^s wM = ComplexNumber.Exp(preFactor * ComplexNumber.ImaginaryOne * 2 * Math.PI / m); // twiddle factor, with prefactor for FFT/IFFT for (int i = 0; i < size; i += m) { w = 1; for (int j = 0; j < shift; j++) { // the call to the reverse bit structure accounts for the bitflipped order even = workF[i + j]; odd = w * workF[i + j + shift]; // joins together the desired even and odd parts, with the twidle factor multiplied to the odd part workF[i + j] = even + odd; workF[i + j + shift] = even - odd; // increase phase of twiddle factor w = w * wM; } } } return(workF); }