Fortran Generating Coordinates for Silver Atoms in C and Fortran

AI Thread Summary
The discussion focuses on converting C code that generates coordinates for simple cubic silver atoms into Fortran. Key issues identified include incorrect array sizes and initialization of variables, particularly the need for 1000-element arrays in C versus 180 in Fortran. Participants emphasize the importance of matching data types, suggesting the use of REAL*8 for double precision, and correcting the indexing of arrays to ensure proper value assignment. Additionally, there are recommendations for improving code readability and formatting to facilitate understanding. The conversation highlights the challenges of translating code between languages while maintaining functionality.
teqnick
Messages
5
Reaction score
0
Hello
Could anyone help me rewrite following C code to Fortran code? It generates coords for sc silver atoms.

Code:
#include <stdio.h>
#include <math.h>

int main(void) {
	int
		i, j, k,
		n = 0;
	double
		A = 4.08,
		L_X = 20.0,
		L_Y = 20.0,
		L_Z = 15.0;
	int
		iMax = ceil(L_X/A),
		jMax = ceil(L_Y/A),
		kMax = ceil(L_Z/A),
		N = (iMax + 1) * (jMax + 1) * (kMax + 1) * 1;
	const int
		NN = 1000;
	double x[NN], y[NN], z[NN];
	
	FILE* fileOut = fopen("Zad-VI.txt", "w");
	FILE* fileOut2 = fopen("Zad-VI.xyz", "w");
    
    for(k = 0; k <= kMax; k++) {
		for(j = 0; j <= jMax; j++) {
			for(i = 0; i <= iMax; i++) {
                x[n] = (i + 0.0) * A;
                y[n] = (j + 0.0) * A;
                z[n] = (k + 0.0) * A;

				n++;
            }
        }
    }
    
	fprintf(fileOut, "# atomN x y z\n");
	for(i = 0; i < N; i++) {
		fprintf(fileOut, "%d %f %f %f\n", i + 1, x[i], y[i], z[i]);
	}
	
	fprintf(fileOut2, "%d\n", N);
	fprintf(fileOut2, "atomName x y z\n");
    for(i = 0; i < N; i++) {
		fprintf(fileOut2, "%s %f %f %f\n", "Ag", x[i], y[i], z[i]);
    }
	    
    fclose(fileOut);
	fclose(fileOut2);
	
    return 0;
}
 
Last edited:
Technology news on Phys.org
What do you have so far and where are you stuck?
 
So far I've got this, but it gives me wrong values

Code:
PROGRAM SC

integer :: i, j, k
integer :: n = 0
REAL :: A = 4.08
REAL :: L_X = 20.0
REAL ::	L_Y = 20.0
REAL :: L_Z = 15.0
INTEGER :: N
INTEGER :: iMax
INTEGER :: jMax 
INTEGER :: kMax 
		
	REAL, DIMENSION(180) :: x
		REAL, DIMENSION(180) :: y
			REAL, DIMENSION(180) :: z
	
OPEN (UNIT=1, FILE='out.xyz', STATUS='REPLACE', ACTION='WRITE', DECIMAL='POINT')

iMax = ceiling(L_X/A)
jMax = ceiling(L_Y/A)
kMax = ceiling(L_Z/A)

    WRITE(*,*) imax, kmax, jmax
    k1: DO k = 1, kmax , 1
		j1:	DO j = 1, jmax, 1
			i1:	DO i = 1, imax, 1
                x = (i + 0.0) * A
                y = (j + 0.0) * A
                z = (k + 0.0) * A

				n=n+1
END DO i1
END DO j1
END DO k1
    

  WRITE(1,200) x, y, z 
		  200 FORMAT (3F10.3) 

END PROGRAM SC
 
I'm not sure this is your problem, but in your fortran code you are using real where the C code uses double. The double type in C is 8 bytes, and I believe real in fortran defaults to 4 bytes. To get a better match, use real*8 for all the variables that are declared as double in the C code.

This code should be very easy to port from C to Fortran if you do exactly the same thing in Fortran that the C code is doing. Unfortunately, your Fortran code departs from what the C code is doing.

For example, in the C code, x, y, and z are 1000-element arrays, but in your Fortran code, each of these is a 180-element array.

Also, there is a variable N in the C code that is initialized like this:
N = (iMax + 1) * (jMax + 1) * (kMax + 1) * 1;
(I have no idea why that 1 appears at the right end.) You don't have this in your Fortran code.
 
U aren't really helping, you just stated the obvious. There is only 180 atoms in sc lattice so there is no need for using 1000 array. There is nothing wrong with REAL declarations.
Also I have no idea what that variable N does in the program. (I have not written that C code, and do not fully understand the C language)
 
fortran:
x = (i + 0.0) * A
y = (j + 0.0) * A
z = (k + 0.0) * A

you multiply whole array. i guess it should be x(n), y(n), z(n).. (?)
 
teqnick said:
U aren't really helping, you just stated the obvious. There is only 180 atoms in sc lattice so there is no need for using 1000 array.
There isn't much in either program that is obvious. There's not a single comment in either program to help a reader understand what the program is trying to do.

I made a comment about the 1000-element arrays and 180-element arrays because I have no knowledge about how many atoms are in an sc lattice (or even what an sc lattice is). There are lots of "magic" numbers such as 4.08, 15.0, and 20.0 whose purpose is a complete mystery to me.
teqnick said:
There is nothing wrong with REAL declarations.
Maybe or maybe not. The person who wrote the C code thought that 8-byte floating point precision should be used, but you have decided that using 4-byte precision is enough. If you need more than 7 decimal places of precision, that smaller data type can make a difference.
teqnick said:
Also I have no idea what that variable N does in the program.
Nor do I. There's also a variable named n that is used in the C version that you don't have.

teqnick said:
(I have not written that C code, and do not fully understand the C language)
 
Pinčiukas said:
fortran:
x = (i + 0.0) * A
y = (j + 0.0) * A
z = (k + 0.0) * A

you multiply whole array. i guess it should be x(n), y(n), z(n).. (?)

Yes of course, but I do not now how to write it in fortran. That why i put it on that forum.

I know where most of the mistakes are, but i do not now how to make it work.
 
The mysterious N variable defines the number of atoms in simple cubic silver lattice, with is 180 so I put an array of the size of 180 instead of N. The L_X, L_Y, L_Z are size of lattice.

Corrected code is below but it still gives me wrong values.

Code:
PROGRAM SC

integer :: i, j, k
integer :: n = 1
REAL :: A = 4.08
REAL :: L_X = 20.0
REAL ::	L_Y = 20.0
REAL :: L_Z = 15.0
INTEGER :: iMax
INTEGER :: jMax 
INTEGER :: kMax 
		
	REAL, DIMENSION(180) :: x
		REAL, DIMENSION(180) :: y
			REAL, DIMENSION(180) :: z
	
OPEN (UNIT=1, FILE='out.xyz', STATUS='REPLACE', ACTION='WRITE', DECIMAL='POINT')

iMax = ceiling(L_X/A)
jMax = ceiling(L_Y/A)
kMax = ceiling(L_Z/A)

    k1: DO k = 1, kmax , 1
		j1: DO j = 1, jmax, 1
			i1: DO i = 1, imax, 1

                x(n) = (i + 0.0) * A
                y(n) = (j + 0.0) * A
                z(n) = (k + 0.0) * A

	     n=n+1

END DO i1
END DO j1
END DO k1
    

  WRITE(1,200) x, y, z 
		  200 FORMAT (3F10.3) 

END PROGRAM SC
 
  • #10
You are still confused about what data type the variables x, y, z are. Each of them is an array, not a single value. If you want to display all the values of these variables, you'll need to use a loop, something like this:
Code:
DO i=0, n
  WRITE (1, 200) x(i), y(i), z(i)
END DO
200 FORMAT (F10.3, 2X, F10.3, 2X, F10.3)
I changed the format statement to add a couple of spaces between successive numbers on a line.

Also, the C code starts off with n = 0, but your code starts off with n = 1. This might make a difference when you get you fortran code running.

Additional comments
1. I don't see any purpose in adding 0.0 as is done in the body of your nested loop. These statements could be written more simply, like this, and should produce the same values.
Code:
     x(n) = i * A
     y(n) = j * A
     z(n) = k * A

2. I find the C code and your FORTRAN code a little difficult to read, due to the random indentation in both. Here is my version of your code, with what I think is more reasonable indentation.
Code:
PROGRAM SC

integer :: i, j, k
integer :: n = 1
REAL :: A = 4.08
REAL :: L_X = 20.0
REAL ::	L_Y = 20.0
REAL :: L_Z = 15.0
INTEGER :: iMax
INTEGER :: jMax 
INTEGER :: kMax 
		
REAL, DIMENSION(180) :: x
REAL, DIMENSION(180) :: y
REAL, DIMENSION(180) :: z
	
OPEN (UNIT=1, FILE='out.xyz', STATUS='REPLACE', ACTION='WRITE', DECIMAL='POINT')

iMax = ceiling(L_X/A)
jMax = ceiling(L_Y/A)
kMax = ceiling(L_Z/A)

k1: DO k = 1, kmax , 1
  j1: DO j = 1, jmax, 1
    i1: DO i = 1, imax, 1
        x(n) = i  * A
        y(n) = j  * A
        z(n) = k * A
        n=n+1
    END DO i1
  END DO j1
END DO k1

DO i=0, n
  WRITE (1, 200) x(i), y(i), z(i)
END DO
200 FORMAT (F10.3, 2X, F10.3, 2X, F10.3)

END PROGRAM SC
 
Back
Top