I am reading an old scientific paper, A MATHEMATICAL MODEL OF PHYSIOLOGICAL TEMPERATURE REGULATION IN MAN and trying to convert the old Fortran program to Matlab.
But I am encountering some problems:
The paper described a program written in FORTRAN. There is two lines with some sort of function DATSW:
CALL DATSW(0,K)
GO TO (951,950), K
.....
.....
CALL DATSW(1,K)
GO TO (917,1102), K
I tried to guess it from the rest of the codes, but its really hard. These two lines of calling DATSW function seem to be very important. Can someone please help me?
A simple Google search lead me to seeing that this exact question was asked on comp.lang.fortran in 2009. A second Google search of datsw fortran led me to this code that comments,
The statement CALL DATSW(NSSW,JUMP) returns JUMP=1 if sense switch number NSSW is on, and JUMP=2 if it is off.
Most of the way down, you can see a dummy version of the code itself.
SUBROUTINE DATSW (NSSW,JUMP)
C
C DUMMY VERSION OF SUBROUTINE DATSW -- ALL SWITCHES OFF.
C
C J. P. CHANDLER, COMPUTER SCIENCE DEPARTMENT,
C OKLAHOMA STATE UNIVERSITY
C
INTEGER NSSW,JUMP
C
JUMP=2
RETURN
END
It seems this code was meant for you to modify to check the switch.
Related
When I run certain programs using FORTRAN 77 with the GNU gfortran compiler I have come across the same problem several times and I'm hoping someone has insight. The value I want should be ~ 1, but it writes out at the end of a program as something well over 10^100. This is generally a problem restricted to arrays for me. The improper value often goes away when I write out the value of this at some stage in the program before (which inevitably happens in trying to troubleshoot the issue).
I have tried initializing arrays explicitly and have tried some array bound checking as well as some internal logical checks in my program. The issue, to me and my research supervisor, seems to be pathological.
WRITE(*,*)"OK9999", INV,INVV
vs
WRITE(*,*)"OK9999", INV,INVV,NP,I1STOR(NP),I2STOR(NP)
The former gives incorrect results for what I would expect for the variables INV and INVV, the latter correct. This is the 'newest' example of this problem, which has on and off affected me for about a year.
The greater context of these lines is:
WRITE(*,*)"AFTER ENERGY",I1STOR(1),I2STOR(1)
DO 167 NP=1!,NV
IF(I1STOR(NP).NE.0) THEN
INV = I1STOR(NP)
INVV = I2STOR(NP)
WRITE(*,*)"OK9999", INV,INVV,NP,I1STOR(NP),I2STOR(NP)
PAUSE
ENDIF
I1STOR(1) and I2STOR(1) are written correctly in the first case "AFTER ENERGY" above. If I write out the value of NP after the DO 167 line, this will also remedy the situation.
My expectation would be that writing out a variable wouldn't affect its value. Often times I am doing large, time-intensive calculations where the ultimate value is way off and in many cases it has traced back to the situation where writing the value out (to screen or file) magically alleviates the problem. Any help would be sincerely appreciated.
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 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.
This is a very simple question, but unfortunately, I am stuck and do not know what to do. My program is a simple program that keeps on accepting 3 numbers and outputs the largest of the 3. The program keeps on running until the user inputs a character.
As the tittle says, my question is how I can make this execute faster ( There will be a large amount of input data ). Any sort of help which may include using a different algorithm or using different functions or changing the entire code is accepted.
I'm not very experienced in C++ Standard, and thus do not know about all the different functions available in the different libraries, so please do explain your reasons and if you're too busy, at least try and provide a link.
Here is my code
#include<stdio.h>
int main()
{
int a,b,c;
while(scanf("%d %d %d",&a,&b,&c))
{
if(a>=b && a>=c)
printf("%d\n",a);
else if(b>=a && b>=c)
printf("%d\n",b);
else
printf("%d\n",c);
}
return 0;
}
It's working is very simple. The while loop will continue to execute until the user inputs a character. As I've explained earlier, the program accepts 3 numbers and outputs the largest. There is no other part of this code, this is all. I've tried to explain it as much as I can. If you need anything more from my side, please ask, ( I'll try as much as I can ).
I am compiling on an internet platform using CPP 4.9.2 ( That's what is said over there )
Any sort of help will be highly appreciated. Thanks in advance
EDIT
The input is made by a computer, so there is no delay in input.
Also, I will accept answers in c and c++.
UPDATE
I would also like to ask if there are any general library functions or algorithms, or any other sort of advise ( certain things we must do and what we must not do ) to follow to speed up execution ( Not just for this code, but in general ). Any help would be appreciated. ( and sorry for asking such an awkward question without giving any reference material )
Your "algorithm" is very simple and I would write it with the use of the max() function, just because it is better style.
But anyway...
What will take the most time is the scanf. This is your bottleneck. You should write your own read function which reads a huge block with fread and processes it. You may consider doing this asynchronously - but I wouldn't recommend this as a first step (some async implementations are indeed slower than the synchronous implementations).
So basically you do the following:
Read a huge block from file into memory (this is disk IO, so this is the bottleneck)
Parse that block and find your three integers (watch out for the block borders! the first two integers may lie within one block and the third lies in the next - or the block border splits your integer in the middle, so let your parser just catch those things)
Do your comparisions - that runs as hell compared to the disk IO, so no need to improve that
Unless you have a guarantee that the three input numbers are all different, I'd worry about making the program get the correct output. As noted, there's almost nothing to speed up, other than input and output buffering, and maybe speeding up decimal conversions by using custom parsing and formatting code, instead of the general-purpose scanf and printf.
Right now if you receive input values a=5, b=5, c=1, your code will report that 1 is the largest of those three values. Change the > comparisons to >= to fix that.
You can minimize the number of comparisons by remembering previous results. You can do this with:
int d;
if (a >= b)
if (a >= c)
d = a;
else
d = c;
else
if (b >= c)
d = b;
else
d = c;
[then output d as your maximum]
That does exactly 2 comparisons to find a value for d as max(a,b,c).
Your code uses at least two and maybe up to 4.
I'm trying to write a C++ program that utilizes a few tens of thousands of lines of Fortran 77 code, but running into some strange errors. I'm passing three coordinates (x,y,z) and the address of three vectors from C++ into fortran, then having fortran run some computations on the initial points and return results in the three vectors.
I do this a few hundred times in a C++ function, leave that function, and then come back to do it again. It works perfectly the first time through, but the second time through it stops returning useful results (returns nan) for points with a positive x component.
Initially it seems like an algorithm problem, except for three things:
It works perfectly the first 200 times I run it
It works if I call it from fortran and eliminate C++ altogether (not viable for the final program)
I've tried adding print statements to fortran to debug where it goes wrong, but turns out if I add print statments to a specific subroutine (even something as simple as PRINT *,'Here'), the program starts returning NaNs even on the first run.
This is why I think it's something to do with how memory is being allocated and deallocated between C and fortran function/subroutine calls. The basic setup looks like this:
C++:
void GetPoints(void);
extern"C"
{
void getfield_(float*,float*,float*,float[],float[],float[],int*,int*);
}
int main(void)
{
GetPoints(); //Works
GetPoints(); //Doesn't
}
void GetPoints(void)
{
float x,y,z;
int i,n,l;
l=50;
n=1;
x=y=z=0.0;
float xx[l],yy[l],zz[l]
for(i=0;i<l;i++)
getfield_(&x,&y,&z,xx,yy,zz,&n,&l);
//Store current xx,yy,zz in large global array
}
Fortran:
SUBROUTINE GETFIELD(XI,YI,ZI,XX,YY,ZZ,IIN,NP)
DIMENSION XX(NP),YY(NP),ZZ(NP)
EXTERNAL T89c
T89c(XI,YI,ZI,XX,YY,ZZ)
RETURN
END
!In T89c.f
SUBROUTINE T89c(XI,YI,ZI,XX,YY,ZZ)
COMMON /STUFF/ ARRAY(100)
!Lots of calculations
!Calling ~20 other subroutines
RETURN
END
Do any of you see any glaring memory issues that I'm creating? Perhaps common blocks that fortran thinks exist but are really deallocated by C++? Without the ability to debug using print statements, nor the time to try to understand the few thousand lines of someone else's Fortran 77 code, I'm open to trying just about anything you all can suggest or think of.
I'm using g++ 4.5.1 for compiling the C++ code and final linking, and gfortran 4.5.1 for compiling the fortran code.
Thanks
**Edit:**
I've tracked the error down to some obscure piece of the code that was written before I was even born. It appears it's looking for some common variable that got removed in the updates over the years. I don't know why it only affected one dimension, nor why the bug was replicatable by adding a print statement, but I've eliminated it nonetheless. Thank you all for the help.
You may be running into the "off-by-one" error. Fortran arrays are 1-based, while C arrays are 0-based. Make sure the array sizes you pass into Fortran are not 1 less than they should be.
Edit:
I guess it looks right... Still, I would try allocating 51 elements in the C++ function, just to see what happens.
By the way float xx[l]; is not standard. This is a gcc feature. Normally you should be allocating memory with new here, or you should be using std::vector.
Also, I am confused by the call to getfield_ in the loop. Shouldn't you be passing i to getfield_?
You should declare XX, YY and ZZ as arrays also in the subroutine T89c as follows:
REAL*4 XX(*)
REAL*4 YY(*)
REAL*4 ZZ(*)
C/C++ should in general never deallocate any Fortran common blocks. These are like structs in C (i.e. memory is reserved at compile time, not at runtime).
For some reason, gfortran seems to accept the following in T89c even without the above declarations:
print *,XX(1)
during compilation but when executing it I get a segmentation fault.