[ anterior ] [ Contenidos ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ 13 ] [ siguiente ]
Fortran 90
para la asignatura Química Computacional
Los objetivos de esta clase son los siguientes:
presentar como se emplea la orden FORMAT, y sus diferentes descriptores con la orden READ.
adquirir conocimientos básicos acerca de la lectura de ficheros en
Fortran
.
dar como alternativas útiles para las operaciones de I/O los here documents y el formato de NAMELIST.
dar un ejemplo de como se puede trabajar con ficheros internos (internal files).
Son similares a los de la clase anterior, aunque en este caso nos centramos en la lectura de datos en Fortran. En general la lectura con formato se emplea al leer datos en ficheros y no al introducir datos con el teclado como entrada estándar.
La orden FORMAT se emplea de igual modo que en las operaciones de escritura tratadas en Operaciones de Entrada/Salida (I/O) (I), Capítulo 6, teniendo los descriptores idéntico significado.
Una opción útil cuando se emplea el comando READ es IOSTAT, que permite detectar si se ha llegado al final del archivo que se esté leyendo o hay un error en la lectura del dato. De este modo el comando quedaría como
READ(UNIT=int_unit, FMT=int_fmt, IOSTAT=int_var) input_list
De este modo, si leemos un conjunto de datos (por ejemplo coordenadas de puntos (var_X,var_Y,var_Z) de un archivo y no sabemos el número total de los mismos podemos hacer algo como
num_data = 0 readloop: DO READ(UNIT=33, FMT=100, IOSTAT=io_status) var_X, var_Y, var_Z ! ! Check reading IF (io_status /= 0) THEN ! Error in the input or EOF EXIT ENDIF num_data = num_dat + 1 ! work with the coordinates ! ...... ! ! Format statement 100 FORMAT(1X, 3F25.10) ! ENDDO readloop
En este fragmento de código la variable entera num_data es un contador que almacena el número de datos (puntos) leídos y la variable entera io_status controla que los datos se hayan leído de forma correcta.
En el ejemplo Programa ejemplo_7_1.f90, Sección 7.3.1 se presenta como se lee un fichero de datos adjunto (notas.dat) usando secciones de matrices en el proceso de lectura. En dicho fichero se ordenan las notas obtenidas por una serie de alumnos en filas y columnas. Cada fila está asociada a un alumno y cada columna a una asignatura. Es conveniente que comprendáis cómo se lleva a cabo la lectura de los datos en este caso.
Se plantea como ejercicio modificar Programa ejemplo_7_1.f90, Sección 7.3.1 para que lleve a cabo la misma tarea con el fichero notas_ej_6.dat, donde no se han llevado a cabo los promedios por alumno ni por asignatura. Partiendo del programa ejemplo debéis realizar los cambios necesarios para leer los datos, comprobar si hay errores de lectura, calcular los promedios necesarios, obtener la salida correcta y grabar un fichero donde aparezcan, como en notas.dat, los promedios calculados.
Una forma bastante cómoda de leer datos en un programa Fortran
es
usando los llamados here documents de la shell
. Esto
consiste en hacer un breve script[9], en el que además de ejecutar el programa -compilándolo
previamente si el programa no es demasiado extenso- se proporciona la entrada
del programa, pudiendo comentarse dichas entradas. El ejemplo Programa ejemplo_7_2.f90, Sección 7.3.2 es un programa
que calcula las raíces de una ecuación de segundo grado y = A*x**2 + B*x
+ C y en el ejemplo Script
ej_here_file, Sección 7.3.3, fichero ej_here_file
encontrais una forma de aplicar los here documents. Para ejecutarlo
tendréis que salvar el fichero y escribir
. ej_here_file
Una tercera posibilidad es hacer uso del llamado namelist que consiste en una lista de valores asignados a variables etiquetadas con sus nombres. La forma de un comando NAMELIST es la siguiente
NAMELIST/var_group_name/ var1 [var2 var3 ... ]
Este comando define las variables asociadas al grupo llamado var_group_name y debe aparecer en el programa antes de cualquier comando ejecutable. Para leer las variables en un NAMELIST se utiliza un comando READ donde en vez de especificar el formato de entrada con la opción FMT se utiliza la opción NML como sigue[10]
READ(UNIT=unit_number, NML=var_group_name, [...])
El fichero NAMELIST con la información de entrada comienza con un carácter "&" seguido del nombre del grupo, var_group_name, y termina con el carácter "/". Los valores en el fichero pueden estar en líneas diferentes siempre que se hallen entre estos dos caracteres.
El programa Programa ejemplo_7_3.f90, Sección 7.3.4 es casi idéntico al programa Programa ejemplo_7_2.f90, Sección 7.3.2. Se ha modificado para hacer uso de un fichero de entrada en formato namelist, que llamamos sec_order.inp e incluimos como namelist input file, Sección 7.3.5.
En Programa ejemplo_7_4.f90, Sección 7.3.6 se puede ver como se trabaja con un fichero interno (internal file) donde la operación de I/O tiene lugar en un buffer interno en lugar de en un archivo. Esto tiene utilidad en dos casos. En primer lugar para tratar con datos cuya estructura o formato no es bien conocida, por lo que se pueden leer en una variable de tipo CHARACTER y posteriormente ser tratados como un fichero interno. En segundo lugar, también permiten preparar datos que sean mezcla de datos de tipo carácter y de tipo numérico. Este segundo caso es el que se trata en Programa ejemplo_7_4.f90, Sección 7.3.6 donde se muestra como definir una serie de unidades de escritura asociadas a archivos que se van numerando sucesivamente.
En este ejemplo se puede ver como se usa la función intrínseca TRIM para eliminar los espacios sobrantes de la variable pref al preparar el nombre del fichero.
PROGRAM EJEMPLO_7_1 IMPLICIT NONE !Definicion de variables INTEGER , PARAMETER :: NROW=5 INTEGER , PARAMETER :: NCOL=6 REAL , DIMENSION(1:NROW,1:NCOL) :: RESULT_EXAMS = 0.0 REAL , DIMENSION(1:NROW) :: MEDIA_ESTUD = 0.0 REAL , DIMENSION(1:NCOL) :: MEDIA_ASIGN = 0.0 INTEGER :: R,C ! ! Abrir fichero para lectura OPEN(UNIT=20,FILE='notas.dat',STATUS='OLD') ! DO R=1,NROW READ(UNIT=20,FMT=100) RESULT_EXAMS(R,1:NCOL),MEDIA_ESTUD(R) ! Lectura de notas y luego de promedio 100 FORMAT(6(2X,F4.1),2X,F5.2) ! Se leen 6 numeros seguidos y luego un septimo ENDDO READ (20,*) ! Saltamos una linea con esta orden READ (20,110) MEDIA_ASIGN(1:NCOL) ! 110 FORMAT(6(2X,F4.1)) ! ! IMPRESION DE LAS NOTAS EN LA SALIDA ESTANDAR DO R=1,NROW PRINT 200, RESULT_EXAMS(R,1:NCOL), MEDIA_ESTUD(R) 200 FORMAT(1X,6(1X,F5.1),' = ',F6.2) END DO PRINT *,' ==== ==== ==== ==== ==== ==== ' PRINT 210, MEDIA_ASIGN(1:NCOL) 210 FORMAT(1X,6(1X,F5.1)) END PROGRAM EJEMPLO_7_1
PROGRAM EJEMPLO_7_2 ! PROGRAMA QUE CALCULA LAS SOLUCIONES DE UNA EC DE SEGUNDO GRADO ! y = A*x**2 + B*x + C IMPLICIT NONE !Definicion de variables REAL :: A = 0.0 REAL :: B = 0.0 REAL :: C = 0.0 REAL, DIMENSION(2) :: SOL REAL :: TEMP INTEGER :: I ! ! Lectura de coeficientes READ*, A READ*, B READ*, C ! print*, a,b,c ! ! CALCULOS TEMP = SQRT(B*B-4.0*A*C) ! SOL(1) = (-B+TEMP)/(2.0*A) SOL(2) = (-B-TEMP)/(2.0*A) ! ! ! IMPRESION DE LAS SOLUCIONES DO I=1, 2 PRINT 200, I, SOL(I) 200 FORMAT(1X,'SOLUCION ', I2,' = ',F18.6) END DO ! END PROGRAM EJEMPLO_7_2
# Compilar gfortran -o second_order ejemplo_7_2.f90 # Ejecutar ./second_order <<eof 2.0 # A 1.0 # B -4.0 # C eof
PROGRAM EJEMPLO_7_3 ! PROGRAMA QUE CALCULA LAS SOLUCIONES DE UNA EC DE SEGUNDO GRADO ! y = A*x**2 + B*x + C IMPLICIT NONE !Definicion de variables REAL :: A = 0.0 REAL :: B = 0.0 REAL :: C = 0.0 REAL, DIMENSION(2) :: SOL REAL :: TEMP INTEGER :: I ! ! NAMELIST DEFINITIONS NAMELIST/INP0/ A, B, C ! NAMELIST FILE OPEN(UNIT=10,FILE='sec_order.inp',STATUS='OLD') ! Lectura de coeficientes READ(10,INP0) ! ! CALCULOS TEMP = SQRT(B*B-4.0*A*C) ! SOL(1) = (-B+TEMP)/(2.0*A) SOL(2) = (-B-TEMP)/(2.0*A) ! ! ! IMPRESION DE LAS SOLUCIONES DO I=1, 2 PRINT 200, I, SOL(I) 200 FORMAT(1X,'SOLUCION ', I2,' = ',F18.6) END DO ! END PROGRAM EJEMPLO_7_3
# # INPUT FILE FOR EJEMPLO_7_3 # &INP0 A=2.0, B=1.0, C=-4.0 /
PROGRAM EJEMPLO_7_4 ! ! Internal file example ! IMPLICIT NONE !Definicion de variables REAL :: x_var INTEGER :: unit_n, index_X CHARACTER(LEN=65) :: filename CHARACTER(LEN=56) :: pref ! PRINT*, "Introduce file name preffix: " READ(*,*) pref ! DO unit_n = 10, 20 ! WRITE(filename, '(A, "_", i2,".dat")') TRIM(pref), unit_n OPEN(UNIT = unit_n, FILE = filename, STATUS = "UNKNOWN", ACTION = "WRITE") ! DO index_X = 0, 100 x_var = REAL(index_X)*0.01 WRITE(unit_n, '(1X,2ES14.6)') x_var, SIN(REAL(unit_n)*x_var) ENDDO ! CLOSE(UNIT = unit_n) ! ENDDO ! END PROGRAM EJEMPLO_7_4
[ anterior ] [ Contenidos ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ 13 ] [ siguiente ]
Lecciones de Fortran 90
para la asignatura Química Computacional
mailto:francisco.perez@dfaie.uhu.es