Related
I am solving the evolution of time dependent schrodinger equation under a harmonic potential and an initial gaussian wavefunction . Treating hcut=1 and 2m=1, and seperating the wavefunction in real and imaginary parts, two coupled equations are obtained in terms of the real and imaginary part, termed as yr and yc respectively.
xrange is [xi,xf]
trange is [0,tf]
method I used is :
first seperating the wavefunction in real and imaginary part, namely yr(x,t) and yc(x,t) .
then treating hcut=2m=1, and writing the wavefunction as yr[x,t]+i*yc[x,t],we get two coupled equations from the TDSE .
1.D[yr[x,t],t]=-D[yc[x,t],x,x]+V[x]*yc[x,t]
2.D[yc[x,t],t]=D[yc[x,t],x,x]-V[x]*yc[x,t]
Then I specified the inital wavefunction as
yr[x,0]=exp[-x^2]
yc[x,0]=0
After that, using finite difference scheme, I tried to find y[x,t] from y[x,0]
i.e,
yr[x,t+d]=yr[x,t]+d*D[yr[x,t],t]
=yr[x,t]+d*(D[yc[x,t],x,x]+V[x]*yc[x,t])
indexed as "a" in code and "b" for the complex part .
The values of y[x[i],t[j]] are stored as y[i,j] as array cannot have real index .
The code I used is given below:
function v(x) result(s)
real::s,x
s=x**2
end function v
real::t(10000),x(10000),yc(10000,10000),yr(10000,10000),tf,xi,xf,d
integer::i,j,k,l,m,n,time
write(*,*) "time of plot divided by step size"
read(*,*) time
tf=50
xi=-10
xf=10
d=0.01
x(1)=xi
t(1)=0
i=1
do while(x(i).lt.xf) !input all values of x in x(i) array
x(i+1)=x(i)+d
i=i+1
end do
n=1
do while(t(n).lt.tf) !input all values of t in t(i) array
t(n+1)=t(n)+d
n=n+1
end do
do j=1,i
yr(j,1)=exp(-(x(j)-5)**2) !input of initial wavefunction
yc(j,1)=0
end do
!calculation of wavefunction at higher time using finite element technique[y[x,t+d]=y[x]+d*D[y[x,t],t] and then replacing the partial derivative with time
!using equation 1 and 2 .
l=1
do while(l.le.i-2)
k=1
do while(t(k).lt.tf)
yr(l,k+1)=yr(l,k)-(yc(l+2,k)-2*yc(l+1,k)+yc(l,k))/d&
+v(x(l))*yc(l,k)*d
yc(l,k+1)=yc(l,k)+(yr(l+2,k)-2*yr(l+1,k)+yr(l,k))/d&
-v(x(l))*yr(l,k)*d
k=k+1
end do
l=l+1
end do
open(1,file="q.dat")
do m=1,i-2
write(1,*) x(m),(yr(m,time))**2+(yc(m,time))**2
end do
close(1)
end
Expected result: y(x,t)^2=yr(x,t)^2+yc(x,t)^2
Error: The wavefunction is not staying regular, after only t=0.05 or 0.06, the wavefunction is turning huge and the maxima is becoming of the order of e30, in spite of that the gaussian shape is remaining almost unchanged, as expected, as only 0.05 seconds has passsed.
This is not really a coding problem but a numerical mathematical one and I suggest you to first study some tutorials about numerical methods for the Schrödinger equation and similar PDEs and then ask for more at sites that are devoted to scientific computation.
First, the method you chose does not conserve the norm of the solution. That can be saved by normalizing by each time step, but it is quite ugly.
Second, the method you chose is explicit (actually, it is probably the forward Euler method that is unconditionally unstable). That means the allovable time step is going to be severly limited by diffusive-like term (even though it is complex here). A simple implicit method that also conserves the norm quite well is the Crank-Nicolson method. It is an implicit method and you will have to solve a system of linear equations at each timestep. It is quite simple in 1D as the system is tridiagonal. There are also some explicit schemes that may work, but they are more involved, not the naive scheme you tried.
Third, you do not have to split the system into the real part and the imaginary part, it can be done using complex numbers.
Fourth, you shoould keep your spatial grid step dx and time-step dt as separate variables with known values. You can compute the final coefficient d as their ratio, but you should at least know your values od dx and dt.
Fifth, you do not have to store all values of the solution in all time-steps. That will quickly become prohibitevely expenses in times of memory required for larger problems. It is enough to store the last time-step and the current time-step. More for multistep methods and some auxiliary steps for Runge-Kutta methods.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
You will need to have read the book to answer my questions.
-Background-
I'm trying to learn Molecular Dynamics and I've started with books that are supposed to be introductory but I'm having a lot of trouble understanding the equations or their explanations. I have tried probably 6 or 7 different books, starting with the introduction chapters and then looking through the book for code I could replicate to give me some context for the equations as I cannot understand them. It's pretty obvious that they expect you to have a lot of prerequisite physics knowledge (and it seems like specifically MD knowledge) to understand how the equations translate to a piece of code. I've taken a physics course and a 3D physics engine course but this knowledge has not been helpful in this endeavor. The only code I've been able to find is in "Understanding Molecular Simulation: From Algorithms to Applications" and I have some questions about it that I cannot find the answers to in the book. If you any prerequisite books or courses that are more beginner friendly to help give me context for the material in this book, that would be amazing -Background End-
This is exactly how the code shows up in the book and I read you're supposed to place subroutines after the main program ends so thats what I did. Because I can only find fortran tutorials that work with very small pieces of code, I'm not sure if I'm supposed to have stop, end, and return at all the places it shows up here, if implicit none is where its supposed to be and if I'm supposed to have each subroutine in a different file or anything like.
The loops are basically the same as in python so I've been able to understand some of the code already but I don't see the larger picture yet.
The main problem I am facing is that a bunch of the variables I used are not declared anywhere in the book (although I found explanations as to what they represent for some of them) which may be why the program won't run. I get this error message "Launch failed. Binary not found".
How do you declare the variables delt, tmax, f(force), en(energy), ranf, lattice_pos, x, v, temp, xm, dt, xr, box, r2i, r6i, ff, xx, and vi? Some of these might not even be variables but I don't think they are built into fortran because I can't find any info on them. Also I'm guessing tmax would be the same number as npart (N particles) so why would they use 2 different variables?
What do these variables mean? (except f and en as I could find them)
Where are the x,y,z coordinates of each atom being stored? I would assume that they would be stored in either 1 list (or whatever the equivalent is in fortran) storing lists with 3 values each (for x,y,z) or 3 lists contaiting all the x,y,z coordinates in each list, in the init subroutine. However that is not the case as only x and and v are looped through.
Why is en an input for force() when it is immediately set to 0 at the beginning of the subroutine? Couldn't you just declare it inside the function without it being an input?
program main
call init
t=0
do while (t.lt.tmax)
call force(f,en)
call integrate(f,en)
t=t+delt
call sample
enddo
stop
end
subroutine init
sumv=0
sumv2=0
do i=1, npart
x(i)=lattice_pos(i)
v(i)=(ranf()-0.5)
sumv=sumv+v(1)
sumv2=sumv2+v(i)**2
enddo
sumv=sumv/npart
sumv2=sumv2/npart
fs=sqrt(3*temp/sumv2)
do i=1,npart
v(i)=(v(i)-sumv)*fs
xm(i)=x(i)-v(i)*dt
enddo
return
subroutine force(f, en)
en=0
do i=1, npart-1
do j=i+1, npart
xr=xr-box*nint(xr/box)
r2=xr**2
if (r2.lt.rc2) then
r2i=1/r2
r6i=r2i**3
ff=48*r2i*r6i*(r6i-0.5)
f(i)=f(i)+ff*xr
f(j)=f(j)-ff*xr
en=en+4*r6i*(r6i-1)-ecut
endif
enddo
enddo
return
end
subroutine integrate(f,en)
sumv=0
sumv2=0
dp i=1,npart
xx=2*x(i)-xm(i)+delt**2*f(i)
vi=(xx-xm(i))/(2*delt)
sumv=sumv+vi
sumv2=sumv2+vi**2
xm(i)=x(i)
x(i)=xx
enddo
temp=sumv2/(3*npart)
etot=(en+0.5*sumv2)/npart
return
end
implicit none
end program main
The example code in "Understanding Molecular Simulation: From Algorithms to Applications", as in many other textbooks, is pseudocode. It is not complete (lack of declarations, for instance) and meant to illustrate the algorithms a bit more explicitly than "just the mathematics". In this book, it is confusing because they write incomplete Fortran for the pseudocode.
This is still a good "general problem": understand how old-fashioned textbook material with Fortran can be used :-)
At http://www.acmm.nl/molsim/frenkel_smit/index.html (website of the Amsterdam Center for Multiscale Modeling), you can find actual Fortran code for the book http://www.acmm.nl/molsim/frenkel_smit/README.html As Ian Bush writes, the code is old-fashioned and the Allen & Tildesley book has an update and updated code: https://github.com/Allen-Tildesley/
As for your questions:
How do you declare the variables delt, tmax, f(force), en(energy), ranf, lattice_pos, x, v, temp, xm, dt, xr, box, r2i, r6i, ff, xx, and vi? Some of these might not even be variables but I don't think they are built into fortran because I can't find any info on them. Also I'm guessing tmax would be the same number as npart (N particles) so why would they use 2 different variables?
You have to read the chapters about the algorithms to make sense of the variables. A list of them is available on page "xxi" of the book however.
Where are the x,y,z coordinates of each atom being stored? I would assume that they would be stored in either 1 list (or whatever the equivalent is in fortran) storing lists with 3 values each (for x,y,z) or 3 lists contaiting all the x,y,z coordinates in each list, in the init subroutine. However that is not the case as only x and and v are looped through.
Here again, the pseudocode is a bit limitative. You have several options declare the variables: (i) The authors (see link above for files) use "common blocks", a Fortran-specific type of global variables. (ii) Module variables, available in Fortran 90 and more recent, are "better global variables". (iii) Encapsulate all the data in derived types that you can declare in the main program and pass to subroutines.
The positions are stored (in the examples) as array x(npmax), y(npmax) and z(npmax). npmax is the maximum number of particles. This is not shown in the pseudo-code. Note that in more recent versions of Fortran (90 and later), you can write vector operations such as x = x + v*dt (where x and v are the position and velocity of all particles and dt is the scalar timestep).
Why is en an input for force() when it is immediately set to 0 at the beginning of the subroutine? Couldn't you just declare it inside the function without it being an input?
It is common, but not mandatory, in Fortran to pass variables that need an update as arguments to subroutine. Programming styles vary.
I have been trying to write a simple program to perform an fft on a 1D input array using fftw3. Here I am using a seismogram as an input. The output array is, however, coming out to contain only zeroes.
I know that the input is correct as I have tried doing the fft of the same input file in MATLAB as well, which gives correct results. There is no compilation error. I am using f95 to compile this, however, gfortran was also giving pretty much the same results. Here is the code that I wrote:-
program fft
use functions
implicit none
include 'fftw3.f90'
integer nl,row,col
double precision, allocatable :: data(:,:),time(:),amplitude(:)
double complex, allocatable :: out(:)
integer*8 plan
open(1,file='test-seismogram.xy')
nl=nlines(1,'test-seismogram.xy')
allocate(data(nl,2))
allocate(time(nl))
allocate(amplitude(nl))
allocate(out(nl/2+1))
do row = 1,nl
read(1,*,end=101) data(row,1),data(row,2)
amplitude(row)=data(row,2)
end do
101 close(1)
call dfftw_plan_dft_r2c_1d(plan,nl,amplitude,out,FFTW_R2HC,FFTW_PATIENT)
call dfftw_execute_dft_r2c(plan, amplitude, out)
call dfftw_destroy_plan(plan)
do row=1,(nl/2+1)
print *,out(row)
end do
deallocate(data)
deallocate(amplitude)
deallocate(time)
deallocate(out)
end program fft
The nlines() function is a function which is used to calculate the number of lines in a file, and it works correctly. It is defined in the module called functions.
This program pretty much tries to follow the example at http://www.fftw.org/fftw3_doc/Fortran-Examples.html
There might just be a very simple logical error that I am making, but I am seriously unable to figure out what is going wrong here. Any pointers would be very helpful.
This is pretty much how the whole output looks like:-
.
.
.
(0.0000000000000000,0.0000000000000000)
(0.0000000000000000,0.0000000000000000)
(0.0000000000000000,0.0000000000000000)
(0.0000000000000000,0.0000000000000000)
(0.0000000000000000,0.0000000000000000)
.
.
.
My doubt is directly regarding fftw, since there is a tag for fftw on SO, so I hope this question is not off topic
As explained in the comments first by #roygvib and #Ross, the plan subroutines overwrite the input arrays because they try the transform many times with different parameters. I will add some practical use considerations.
You claim you do care about performance. Then there are two possibilities:
You do the transform only once as you show in your code. Then there is no point to use FFTW_MEASURE. The planning subroutine is many times slower than actual plan execute subroutine. Use FFTW_ESTIMATE and it will be much faster.
FFTW_MEASURE tells FFTW to find an optimized plan by actually
computing several FFTs and measuring their execution time. Depending
on your machine, this can take some time (often a few seconds).
FFTW_MEASURE is the default planning option.
FFTW_ESTIMATE specifies that, instead of actual measurements of
different algorithms, a simple heuristic is used to pick a (probably
sub-optimal) plan quickly. With this flag, the input/output arrays are
not overwritten during planning.
http://www.fftw.org/fftw3_doc/Planner-Flags.html
You do the same transform many times for different data. Then you must do the planning only once before the first transform and than re-use the plan. Just make the plan first and only then you fill the array with the first input data. Making the plan before every transport would make the program extremely slow.
I have been looking at an engineering paper here which describes an old FORTRAN code for solving pipe flow equations (it's dated 1974, before FORTRAN was standardised as Fortran 77). On page 42 of this document the old code calls the following subroutine:
C SYSTEM SUBROUTINE FROM UNIVAC MATH-PACK TO
C SOLVE LINEAR SYSTEM OF EQ.
CALL GJR(A,51,50,NP,NPP,$98,JC,V)
It's a bit of a long shot, but do any veterans or ancient code buffs recall this system subroutine and it's input arguments? I'm having trouble finding any information about it.
If I can adapt the old code my current application I may rewrite this in C++ or VBA, and will be looking for an equivalent function in these languages.
I'll add to this answer if I find anything more detailed, but I have a place to start looking for the arguments to GJR.
This function is part of the Sperry UNIVAC MATH-PACK library - a full list of functions in the library can be found in http://www.dtic.mil/dtic/tr/fulltext/u2/a170611.pdf GJR is described as "determinant; inverse; solution of simultaneous equations". Marginally helpful.
A better description comes from http://nvlpubs.nist.gov/nistpubs/jres/74B/jresv74Bn4p251_A1b.pdf
A FORTRAN subroutine, one of the Univac 1108 Math Pack programs,
available on the library tapes at the University of Maryland computing
center. It solves simultaneous equations, computes a determinant, or
inverts a matrix or any combination of the three above by using a
Gauss-Jordan elimination technique with column pivoting.
This is slightly more useful, but what we really want is "MATH-PACK, Programmer Reference", UP-7542 Rev. 1 from Sperry-UNIVAC (Unisys) I find a lot of references to this document but no full-text PDF of the document itself.
I'd take a look at the arguments in the function call, how they are set up and how the results are used, then look for equivalent routines in LAPACK or BLAS. See http://www.netlib.org/lapack/
I have a few books on piping networks including "Analysis of Flow in Pipe Networks" by Jeppson (same author as in the original PDF hosted by USU) https://books.google.com/books/about/Analysis_of_flow_in_pipe_networks.html?id=peZSAAAAMAAJ - I'll see if I can dig that up. The book may have a more portable matrix solver than the proprietary Sperry-UNIVAC library.
Update:
From p. 41 of http://ngds.egi.utah.edu/files/GL04099/GL04099_1.pdf I found documentation for the CGJR function, the complex version of GJR from the same library. It is likely the only difference in the arguments is variable type (COMPLEX instead of REAL):
CGJR is a subroutine which solves simultaneous equations, computes a determinant, inverts a matrix, or does any combination of these three operations, by using a Gauss-Jordan elimination technique with column pivoting.
The procedure for using CGJR is as follows:
Calling statement: CALL CGJR(A,NC,NR,N,MC,$K,JC,V)
where
A is the matrix whose inverse or determinant is to be determined. If simultaneous equations are solved, the last MC-N columns of the matrix are the constant vectors of the equations to be solved. On output, if the inverse is computed, it is stored in the first N columns of A. If simultaneous equations are solved, the last MC-N columns contain the solution vectors. A is a complex array.
NC is an integer representing the maximum number of columns of the array A.
NR is an integer representing the maximum number of rows of the array A.
N is an integer representing the number of rows of the array A to be operated on.
MC is the number of columns of the array A, representing the coefficient matrix if simultaneous equations are being solved; otherwise it is a dummy variable.
K is a statement number in the calling program to which control is returned if an overflow or singularity is detected.
1) If an overflow is detected, JC(1) is set to the negative of the last correctly completed row of the reduction and control is then returned to statement number K in the calling program.
2) If a singularity is detected, JC(1)is set to the number of the last correctly completed row, and V is set to (0.,0.) if the determinant was to be computed. Control is then returned to statement number K in the calling program.
JC is a one dimensional permutation array of N elements which is used for permuting the rows and columns of A if an inverse is being computed .. If an inverse is not computed, this array must have at least one cell for the error return identification. On output, JC(1) is N if control is returned normally.
V is a complex variable. On input REAL(V) is the option indicator, set as follows:
invert matrix
compute determinant
do 1. and 2.
solve system of equations
do 1. and 4.
do 2. and 4.
do 1., 2. and 4.
Notes on usage of row dimension arguments N and NR:
The arguments N and NR refer to the row dimensions of the A matrix.
N gives the number of rows operated on by the subroutine, while NR
refers to the total number of rows in the matrix as dimensioned by the
calling program. NR is used only in the dimension statement of the
subroutine. Through proper use of these parameters, the user may specify that only a submatrix, instead of the entire matrix, be operated on by the subroutine.
In your application (pipe flow), look at how matrix A and vector V are populated before the call to GJR and how they are used after the call.
You may be able to replace the call to GJR with a call to LAPACK's SGESV or DGESV without much difficulty.
Aside: The Fortran community really needs a drop-in 'Rosetta library' that wraps LAPACK, etc. for replacing legacy/proprietary IBM, UNIVAC, and Numerical Recipes math functions. The perfect case would be that maintainers would replace legacy functions with de facto standard math functions but in the real world, many of these older programs are un(der)maintained and there simply isn't the will (or, as in this case, the ability) to update them.
Update 2:
I started work on a compatibility library for the Sperry MATH-PACK and STAT-PACK routines as well as a few other legacy libraries, posted at https://bitbucket.org/apthorpe/alfc
Further, I located my copy of Jeppson's Analysis of Flow in Pipe Networks which is a slightly more legible version of the PDF of Steady Flow Analysis of Pipe Networks: An Instructional Manual and modernized the codes listed in the text. I have posted those at https://bitbucket.org/apthorpe/jeppson_pipeflow
Note that I found a number of errors in both the code listings and in the example problems given for many of the codes. If you're trying to learn how to write a pipe flow solver based on Jeppson's paper or text, I'd strongly suggest reviewing my updated codes and test cases because they will save you hours of effort trying to understand why the code doesn't work and why you can't replicate the example cases. This took a fair amount of forensic computing to sort out.
Update 3:
The source to CGJR and DGJR can be found in http://www.dtic.mil/dtic/tr/fulltext/u2/a110089.pdf. DGJR is the closest to what you want, though it references more routines that aren't available (proprietary UNIVAC error-handling routines). It should be easy to convert `DGJR' to single precision and skip the proprietary calls. Otherwise, use the compatibility library mentioned above.
As the title states I'm using FFTW (version 3.2.2) with Fortran 90/95 to perform a 2D FFT of real data (actually a field of random numbers). I think the forward step is working (at least I am getting some ouput). However I wanted to check everything by doing the IFFT to see if I can re-construct the original input. Unfortunately when I call the complex to real routine, nothing happens and I obtain no error output, so I'm a bit confused. Here are some code snippets:
implicit none
include "fftw3.f"
! - im=501, jm=401, and lm=60
real*8 :: u(im,jm,lm),recov(im,jm,lm)
complex*8 :: cu(1+im/2,jm)
integer*8 :: planf,planb
real*8 :: dv
! - Generate array of random numbers
dv=4.0
call random_number(u)
u=u*dv
recov=0.0
k=30
! - Forward step (FFT)
call dfftw_plan_dft_r2c_2d(planf,im,jm,u(:,:,k),cu,FFTW_ESTIMATE)
call dfftw_execute_dft_r2c(planf,u(:,:,k),cu)
call dfftw_destroy_plan(planf)
! - Backward step (IFFT)
call dfftw_plan_dft_c2r_2d(planb,im,jm,cu,recov(:,:,k),FFTW_ESTIMATE)
call dfftw_execute_dft_c2r(planb,cu,recov(:,:,k))
call dfftw_destroy_plan(planb)
The above forward step seems to work (r2c) but the backward step does not seem to work. I checked this by differencing the u and recov arrays - which ended up not being zero. Additionally the max and min values of the recov array were both zero, which seems to indicate that nothing was changed.
I've looked around the FFTW documentation and based my implementation on the following page http://www.fftw.org/fftw3_doc/Fortran-Examples.html#Fortran-Examples . I am wondering if the problem is related to indexing, at least that's the direction I am leaning. Anyway, if any one could offer some help, that would be wonderful!
Thanks!
Not sure if this is the root of all troubles here, but the way you declare variables may be the culprit.
For most compilers (this is apparently not even a standard), Complex*8 is an old syntax for single precision: the complex variable occupies a total of 8 bytes, shared between the real and the imaginary part (4+4 bytes).
[Edit 1 following Vladimir F comment to my answer, see his link for details:] In my experience (i.e. the systems/compiler I ever used), Complex(Kind=8) corresponds to the declaration of a double precision complex number (a real and an imaginary part, both of which occupy 8 bytes).
On any system/compiler, Complex(Kind=Kind(0.d0)) should declare a double precision complex.
In short, your complex array does not have the right size. Replace occurences of Real*8 and Complex*8 by Real(kind=8) and Complex(Kind=8) (or Complex(Kind=kind(0.d0)) for a better portability), respectively.