[ 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 es posible aprovechar el redireccionamiento de la entrada y
salida estándar en UNIX
para la lectura y escritura de datos en
Fortran
.
presentar la orden FORMAT, sus diferentes descriptores y cómo se define un formato que combina con las órdenes PRINT y WRITE.
adquirir conocimientos básicos acerca del uso de ficheros en
Fortran
con las órdenes OPEN, CLOSE,
WRITE.
En esta clase, salvo en el primer punto mencionado, que es general, nos
centramos en las operaciones de salida desde el programa Fortran
,
mientras que la siguiente clase se dedica a aplicar lo aprendido a la lectura
de datos desde Fortran
.
Redireccionamiento en UNIX
El redireccionado de la entrada y salida estándar (STDIN/STDOUT)
mediante los símbolos < y > permite, sin
controlar en principio los formatos, desviar del teclado y de la pantalla la
entrada y la salida estándar de un programa Fortran
.
Por ejemplo, los siguientes comandos hacen que al correr un programa llamado a.out su salida se dirija al fichero output.dat en el primer caso. En el segundo caso el programa lee su entrada de un fichero llamado output.dat mientras que en el tercer caso combinamos ambos procedimientos.
a.out > output.dat a.out < input.dat a.out <input.dat > output.dat
El ejercicio propuesto número 4 se facilita mucho si se tiene esto en cuenta.
Puede redireccionarse también la salida de error (STDERR) como
a.out 2> output.dat a.out 2>&1 input.dat
En el segundo case se unen ambas salidas, STDERR y STDOUT
Para que se tenga un mayor control del formato de las entradas y salidas se combinan las órdenes de entrada (READ) y salida (PRINT) con los llamados descriptores de formato. Hasta ahora hemos usado estas órdenes con los formatos por defecto, usando el llamado formato libre: READ(*,*) o READ* y PRINT*. Para especificar un formato dado a estos comandos se suelen usar en la forma PRINT nlin, output_list, donde nlin es una etiqueta que indica un comando FORMAT que proporciona los necesarios descriptores de formato y output_list son las variables y constantes que deseamos imprimir. Ocurre de manera similar con la orden READ. Veremos diferentes ejemplos al explicar los diferentes descriptores de formato posibles. Veremos también que es posible incluir el formato directamente en la orden PRINT.
Los descriptores de formato en FORTRAN
están influenciados por el
hecho de que el dispositivo de salida habitual cuando se desarrolló este
lenguaje era la impresora de línea. Por ello el primer carácter es un carácter
de control de modo que si el primer carácter es
0 : espaciado doble.
1 : salta a nueva página.
+ : sin espaciado, imprime la línea sobre la línea anterior.
blank : espaciado simple
Veremos los diferentes descriptores de formato: descriptores para fijar la posición vertical de una línea de texto, para alterar la posición horizontal de los caracteres en una línea, descriptores para mostrar adecuadamente datos enteros (I), reales (F y E), caracteres A y variables lógicas (L).
Usamos los siguientes símbolos
c : número de columna
d : número de dígitos tras el punto decimal (valores reales)
m : número mínimo de dígitos mostrados
n : número de espacios
r : número de veces que se repite un determinado descriptor
w : número de caracteres a los que afecta un determinado descriptor
Se explica en primer lugar el uso de los descriptores con operaciones de salida.
Descriptor de enteros I:
Su forma general es rIw o rIw.m. Este descriptor indica que se van a leer o escribir r enteros que ocupa w caracteres o columnas. El número se justifica a la derecha, por lo que si es menor el número de dígitos que el previsto se rellena de espacios a la izquierda del número. Por ejemplo
PRINT 100, I, I*I 100 FORMAT(' ',I3, ' AL CUADRADO ES ', I6)
imprime un espacio, tras él un número entero de como máximo tres dígitos. Luego imprime la cadena 'AL CUADRADO ES' y termina con el número al cuadrado, que se prevé que ocupará como máximo seis dígitos. Para ver un ejemplo de uso de este descriptor así como para ver qué ocurre si se supera el número máximo de dígitos permitidos puede usarse el ejemplo Programa ejemplo_6_1.f90, Sección 6.3.1. En este ejemplo incluimos el descriptor X, donde nX implica que se incluyan n espacios en la salida.
Si en el ejemplo anterior se desea introducir el formato en la orden PRINT tendríamos
PRINT "(' ',I3, ' AL CUADRADO ES ', I6)", I, I*I
Como puede verse en la salida del ejemplo Programa ejemplo_6_1.f90, Sección 6.3.1 tenemos un desbordamiento aritmético de la variable big, ya que es una variable de 32 bits, tras lo cual la salida obtenida no tiene sentido alguno. Para resolver este problema podemos definir la variable como variable de 64 bits, como en el ejemplo Programa ejemplo_6_2.f90, Sección 6.3.2. En este ejemplo podemos ver lo que ocurre cuando el formato no cuenta con tamaño suficiente para acomodar el resultado del cálculo.
Descriptor de reales F:
Su forma más general es rFw.d, siendo w el número total de columnas empleadas en la representación del número y d el número de dígitos tras el punto decimal. Por ejemplo F7.3 implica que el número tiene tres decimales, más el punto decimal, por lo que quedan tres dígitos no decimales, esto es, sería valido para números entre -99.999 y 999.999. Si se trunca la parte decimal se redondea adecuadamente. Es importante tener en cuenta que a veces el redondeo hará que el número tenga más cifras de las previstas y la salida se verá sustituida por una serie de asteriscos (*). En el ejemplo Programa ejemplo_6_3.f90, Sección 6.3.3 vemos el uso de este formato así como los posibles problemas que puede conllevar cuando las cifras implicadas no se adaptan adecuadamente al formato previsto.
Descriptor de reales E:
Permite el uso de la notación científica. Su forma general es rEw.d. El número que multiplica a la potencia de 10 toma valores entre 0.1 y 1.0. Este caso se distingue del anterior porque hay que reservar sitio para el exponente. De hecho es necesario un carácter para el punto decimal, otro para E (el indicador de exponente, que implica la potencia de diez por la que se multiplica el número), el signo del número completo, la magnitud del exponente y el signo del exponente. Por tanto, el tamaño mínimo en este caso es w = d+7. El ejemplo Programa ejemplo_6_4.f90, Sección 6.3.4 es idéntico al ejemplo Programa ejemplo_6_3.f90, Sección 6.3.3 sustituyendo los descriptores F por E. Como puede verse en este ejemplo, este formato es muy adecuado cuando se debe trabajar con valores que abarquen un gran rango de variación.
Descriptor de reales ES:
Permite el uso de la notación científica estándar. Su forma general es rESw.d. El número que multiplica a la potencia de 10 toma valores entre 1.0 y 10.0. Aparte de esto, este caso es muy similar al anterior
Descriptor de datos lógicos L:
Este descriptor aparece en la forma rLw. Estos datos solo pueden tomar los valores TRUE y FALSE y la salida de este descriptor será T o F justificado a la derecha.
Descriptor de caracteres A:
Este descriptor aparece en la forma rA o rAw. En el primer lugar se indica que se repiten r veces formatos de caracteres con una anchura igual al número de caracteres de los que consta la variable. En el segundo caso la salida tiene una anchura fija dada por w. El ejemplo Programa ejemplo_6_5.f90, Sección 6.3.5 muestra el uso de este descriptor.
Descriptor X:
El descriptor nX controla el desplazamiento horizontal e indica que se escriban n espacios en la salida. El ejemplo Programa ejemplo_6_5.f90, Sección 6.3.5 muestra el uso de este descriptor combinado con los anteriores.
Descriptor T:
El descriptor Tc controla el desplazamiento horizontal e indica que se salte directamente a la columna c.
Descriptor /:
El descriptor /c envía la salida acumulada hasta el momento a STDOUT y comienza un nuevo registro con un retorno de carro. Este descriptor no necesita ser separado del resto mediante comas. Tras cada retorno de carro puede ubicarse un carácter de control.
Repetición:
En todos los casos descritos se puede indicar la repetición de formato usando un número a la derecha del símbolo que indica el formato. Por ejemplo,
100 FORMAT(1X, 2I6, 3F9.3)
es equivalente a
100 FORMAT(1X, I6, I6, F9.3, F9.3, F9.3)
y se puede simplificar a
100 FORMAT(1X, 3(I6, F9.3))
Es también necesario citar el significado especial que tiene un formato entre paréntesis en una orden FORMAT y lo que sucede si el número de datos proporcionado en la lista de variables de la orden WRITE es mayor o menor que el número de descriptores asociados en la correspondiente orden FORMAT.
Fortran
permite la manipulación de ficheros. En este caso vamos a
concentrarnos en como se crean y se escriben ficheros. Para ello se utilizan
las órdenes básicas OPEN, WRITE y CLOSE.
Otras órdenes de interés son REWIND y BACKSPACE.
La orden OPEN permite que se abra un fichero, en su forma más simple sería
OPEN(UNIT=int_unit,FILE='nombre_fichero')
donde se indica el nombre del fichero creado y el número de unidad asociada a dicho fichero (número entero). Para operaciones de lectura y escritura el fichero queda asociado a este número. Un ejemplo de esto sería escribir algo en este fichero usaremos una orden como
OPEN(UNIT=33, FILE='output_program.dat') WRITE(UNIT=33,FMT=100) lista_de_variables
lo que indica que envíe los datos en lista_de_variables al fichero
asociado a la unidad 33, llamado output_program.dat
, según el
formato especificado en la línea etiquetada como 100. Es posible
usar la forma abreviada WRITE(33,100) e incluso
WRITE(33,*) si queremos escribir en el fichero con el formato
estándar dependiente de la lista de variables. Para escribir en la salida
estándar STDOUT, en principio la pantalla, se puede usar
WRITE(6,formato), ya que esta salida está asociada a la
unidad 6. Por tanto WRITE(6,*) es equivalente a
PRINT*, mientras que STDIN se asocia a la unidad
5[8]. Para referirnos
a STDOUT y STDIN es más conveniente usar el carácter
* ya que los números anteriores pueden depender del procesador.
Una vez que el proceso de escritura ha terminado el fichero se cierra con la orden CLOSE(UNIT=numero_unidad). En nuestro caso
CLOSE(UNIT=33)
El ejemplo Programa ejemplo_6_6.f90, Sección 6.3.6
muestra como se escribe a un fichero e introduce la función intrínseca de
Fortran
CPU_TIME que nos permite estimar el tiempo de
cpu dedicado a cada parte del programa.
La orden OPEN puede especificarse de forma más detallada con los argumentos siguientes:
OPEN(UNIT=int_unit,FILE=char_nombre_fichero,STATUS=char_sta, ACTION=char_act, IOSTAT=int_stat)
Las nuevas opciones fijan los siguientes aspectos al abrir el fichero:
STATUS=char_sta
La constante o variable char_sta es de tipo carácter y puede tomar los siguientes valores estándar:
'OLD'
'NEW'
'REPLACE'
'SCRATCH'
'UNKNOWN'
ACTION=char_act
La constante o variable char_act es de tipo carácter y puede tomar los siguientes valores estándar:
'READ'
'WRITE'
'READWRITE'
Por defecto, si no se da otra opción, desde Fortran
, los archivos
se abren con los permisos activados tanto de lectura como de escritura.
IOSTAT=int_var
La constante o variable int_stat es de tipo entero y permite estimar si la apertura y el acceso al fichero ha sido exitosa. Si el valor que devuelve es 0 quiere decir que la apertura se ha resuelto sin problemas. Si ha habido problemas al abrir el fichero devuelve un valor diferente de cero.
Un ejemplo más completo que el anterior, creando un fichero de entrada (INPUT) sería
INTEGER ierror OPEN(UNIT=33, FILE='input_program.dat', STATUS='OLD', ACTION='READ', IOSTAT=ierror)
Para crear un fichero de salida se hace
INTEGER ierror OPEN(UNIT=33, FILE='output_program.dat', STATUS='NEW', ACTION='WRITE', IOSTAT=ierror)
Es posible controlar de forma rudimentaria el acceso a los elementos almacenados en el fichero secuencial creado con la orden OPEN. Para ello existen dos comandos de interés.
BACKSPACE(UNIT = int_unit) REWIND(UNIT = int_unit)
Con BACKSPACE se retrocede un registro (una línea) en el fichero asociado a la unidad int_unit. Con REWIND se vuelve al primer registro del fichero.
Hasta ahora hemos empleado la orden OPEN con ficheros con formato, siendo este el comportamiento por defecto al abrir un fichero. Por tanto, las órdenes
OPEN(UNIT=33,FILE='nombre_fichero') OPEN(UNIT=33,FILE='nombre_fichero',FORM='FORMATTED')
son equivalentes. Los ficheros con formato tienen la ventaja de ser editables por el usuario, pero precisan de un mayor tiempo para su lectura y escritura que cuando se tratan los datos sin formato. Para ello se abren los ficheros con la opción FORM='UNFORMATTED' como en el ejemplo siguiente
OPEN(UNIT=33,FILE='nombre_fichero',FORM='UNFORMATTED')
Además, que los fichero no tengan formato permite almacenar números reales sin la pérdida de información que implica el cambio a un formato dado. En el Ejercicio 5 se pide que transforméis el ejemplo Programa ejemplo_6_6.f90, Sección 6.3.6 para comprobar el tiempo que se tarda en la escritura y lectura sin formato. Al escribir en un fichero sin formato no se indica ningún formato en la orden, de manera que para escribir en el fichero sin formato que hemos abierto asociado con UNIT=33 haremos
WRITE(UNIT=33) lista-de-variables
PROGRAM ej_6_1 ! IMPLICIT NONE INTEGER :: i, big=10 ! DO i=1,18 PRINT 100, i, big 100 FORMAT(1X, '10 elevado a ',I3,2X,'=',2X,I12) big=big*10 END DO END PROGRAM ej_6_1
PROGRAM ejemplo_6_2 ! IMPLICIT NONE ! INTEGER, PARAMETER :: Long=SELECTED_INT_KIND(16) ! Tipo de entero de 64 bits INTEGER :: i INTEGER (KIND = Long) :: big=10 ! DO i=1,18 ! PRINT 100, i, big 100 FORMAT(1X, '10 elevado a ',I3,2X,'=',2X,I16) ! big=big*10 ! END DO ! END PROGRAM ejemplo_6_2
PROGRAM ej_6_3 ! Programa que hace patente problemas de desbordamiento ! aritmetico por exceso y por defecto. IMPLICIT NONE INTEGER :: I REAL :: peq = 1.0 REAL :: gran = 1.0 ! DO i=1,45 PRINT 100, I, peq, gran 100 FORMAT(' ',I3,' ',F9.4,' ',F9.4) ! peq=peq/10.0 gran=gran*10.0 ! END DO END PROGRAM ej_6_3
PROGRAM ej_6_4 ! Programa que hace patente problemas de desbordamiento ! aritmético por exceso y por defecto. IMPLICIT NONE INTEGER :: I REAL :: peq = 1.0 REAL :: gran = 1.0 ! DO i=1,45 PRINT 100, I, peq, gran 100 FORMAT(' ',I3,' ',E10.4,' ',E10.4) ! peq=peq/10.0 gran=gran*10.0 ! END DO END PROGRAM ej_6_4
PROGRAM ej_6_5 ! Programa que calcula el IMC o indice de Quetelet. ! Se hace según la expresión matemática: ! IMC=(peso (kg))/(talla^2 (m^2)) ! IMPLICIT NONE CHARACTER (LEN=25) :: NOMBRE INTEGER :: hcm = 0, peso = 0 ! altura en cm y peso en kg REAL :: talla = 0.0 ! altura en metros REAL :: IMC ! Indice de masa corporal ! PRINT*, 'Introduzca su nombre de pila:'; READ*, NOMBRE ! PRINT*, 'Introduzca su peso en kilogramos:'; READ*, peso ! PRINT*, 'Introduzca su altura en centimetros:'; READ*, hcm ! talla = hcm/100.0 IMC = peso/(talla**2) ! PRINT 100, NOMBRE, IMC, IMC 100 FORMAT(1X,'El IMC de ',A,' es ',F10.4,' o ',E10.4) ! END PROGRAM ej_6_5
PROGRAM ej_6_6 ! IMPLICIT NONE INTEGER , PARAMETER :: N=1000000 INTEGER , DIMENSION(1:N) :: X REAL , DIMENSION(1:N) :: Y INTEGER :: I REAL :: T REAL , DIMENSION(1:5) :: TP CHARACTER(LEN = 10) :: COMMENT ! OPEN(UNIT=10,FILE='ej_6_6.txt') ! CALL CPU_TIME(T) ! TP(1)=T COMMENT=' T INICIAL ' PRINT 100,COMMENT,TP(1) ! DO I=1,N X(I)=I END DO ! CALL CPU_TIME(T) ! TP(2)=T-TP(1) COMMENT = ' VAR ENTERA ' PRINT 100,COMMENT,TP(2) ! Y=REAL(X) ! CALL CPU_TIME(T) ! TP(3)=T-TP(1)-TP(2) COMMENT = ' VAR REAL ' ! PRINT 100,COMMENT,TP(3) ! DO I=1,N WRITE(10,200) X(I) 200 FORMAT(1X,I10) END DO ! CALL CPU_TIME(T) TP(4)=T-TP(1)-TP(2)-TP(3) ! COMMENT = ' WRITE INTEG ' PRINT 100,COMMENT,TP(4) ! DO I=1,N WRITE(10,300) Y(I) 300 FORMAT(1X,f10.0) END DO ! CALL CPU_TIME(T) TP(5)=T-TP(1)-TP(2)-TP(3)-TP(4) ! COMMENT = ' WRITE REAL ' PRINT 100,COMMENT,TP(5) 100 FORMAT(1X,A,2X,F7.3) END PROGRAM ej_6_6
[ 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