[ 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 el orden natural en el que se almacenan los elementos en matrices multidimensionales.
presentar como se pueden manipular matrices completas y secciones de matrices
en Fortran
.
ver como se puede trabajar con parte de una matriz.
explicar la definición de matrices con la orden WHERE.
Orden de almacenamiento
El orden en el que se almacenan los elementos de una matriz multidimensional en
Fortran
es tal que el primer subíndice varía más rápidamente, a
continuación el segundo, a continuación el tercero y así sucesivamente. Es lo
que se conoce como column major order.
Por ejemplo, si definimos una matriz con dos subíndices y de dimensión 4x2 con la orden
REAL , DIMENSION(1:4,1:2) :: A,
Esta matriz A tiene ocho elementos que se guardan en memoria siguiendo el orden
A(1,1), A(2,1), A(3,1), A(4,1), A(1,2), A(2,2), A(3,2), A(4,2)
Por tanto para inicializar la matriz A podemos hacerlo de diferentes maneras. Supongamos que queremos inicializar la matriz de modo que cada elemento sea igual al número de su fila. Podemos usar dos bucles[4]
DO I_col = 1, 2 DO I_row = 1, 4 A(I_row, I_col) = I_row ENDDO ENDDO
Podemos también hacer uso de un array constructor, aunque la solución que parece más lógica, haciendo
A = (/ 1, 2, 3, 4, 1, 2, 3, 4 /)
no funciona. El array constructor produce un vector de dimensión ocho, y no una matriz 4x2. Este vector y la matriz A tiene idéntico tamaño, pero no son conformables. Para resolver este problema es preciso hacer uso de la orden RESHAPE. La sintaxis de esta orden es la siguiente
output_array = RESHAPE(array_1, array_2)
Donde array_1 contiene es una matriz los datos que van a sufrir el cambio, array_2 es un vector que describe las dimensiones de la nueva matriz output_array. El número de elementos, esto es, el tamaño, de las matrices array_1 y output_array debe ser idéntico. En el caso anterior podemos por tanto hacer
A = RESHAPE( (/ 1, 2, 3, 4, 1, 2, 3, 4 /), (/ 4, 2 /) )
En Programa ejemplo_4_3.f90, Sección 4.3.3 se puede ver otro ejemplo. El comando RESHAPE puede usarse en la declaración del arreglo
INTEGER, DIMENSION(1:4,1:2) :: A = & RESHAPE( (/ 1, 2, 3, 4, 1, 2, 3, 4 /), (/ 4, 2 /) )
El orden seguido en el almacenamiento de los datos es especialmente importante en las operaciones de entrada y salida. Si ejecutamos
PRINT*, A
El resultado será
A(1,1), A(2,1), A(3,1), A(4,1), A(1,2), A(2,2), A(3,2), A(4,2)
Es preciso tener esto en cuenta al utilizar READ para leer los elementos de un arreglo en un fichero, haciendo READ(unit,*) A. Para cambiar el orden de lectura es posible hacer uso de implicit DO's
READ(unit,*) ( ( A(row,col), col = 1, 2 ), row = 1, 4 )
En FORTRAN
es posible definir arreglos multidimensionales más allá
de las matrices, siendo 7 el límite del número de índices y corriendo más
rápidamente el primero, luego el segundo, y así sucesivamente hasta el último.
En el ejemplo Programa ejemplo_4_2.f90, Sección
4.3.2 se caracteriza de forma completa un arreglo haciendo uso de varias de
funciones de tipo. inquiry (ver Programa ejemplo_8_2.f90, Sección
8.3.2).
Es importante al explicar el material de esta clase hacer énfasis en los siguientes puntos que afectan al manejo de matrices completas. Si por ejemplo definimos los vectores reales V1, V2, V3 y V4 como
REAL , DIMENSION(1:21) :: V1, V2 REAL , DIMENSION(-10:10) :: V3 REAL , DIMENSION(0:10) :: V4
Podemos trabajar de forma natural con estos vectores completos como en los siguientes ejemplos[5].
Asignación de un valor:
V1 = 0.5
Hacemos que todos los elementos de V1 sean iguales a 0.5.
Igualar matrices:
V1 = V2
Hacemos que cada elemento de V1 sea igual al elemento equivalente de V2. Esta función sólo es aplicable a matrices conformables[6]. Por ejemplo, también es válido hacer
V3 = V2
pero no es válido
V1 = V4
Todas las operaciones aritméticas aplicables a escalares se pueden asimismo aplicar a matrices, siempre que estas sean conformables, aunque hay que tener claro qué implican pues es posible que matemáticamente no tengan sentido. Usando los mismos vectores que en el punto anterior podemos hacer
V1 = V2 + V3 V1 = V2*V3
En el primer caso V1 es la suma de los dos vectores, pero en el segundo V1 es un vector, cada uno de sus elementos es el producto de los elementos correspondientes de V2 y V3. Esto no es el producto escalar de dos vectores. Como hemos indicado, este caso de nuevo las matrices han de ser conformables. Para matrices bidimensionales, por ejemplo, si definimos las matrices
REAL , DIMENSION(1:4,1:4) :: A, B, C
Pueden hacerse operaciones como las siguientes
A = A**0.5 C = A + B C = A * B
Es importante tener en cuenta que la última operación no es el producto de dos matrices, sino otra matriz, de idéntica dimensión a las de A y B, y cada uno de sus elementos es el producto de los correspondientes elementos de A y B.
También pueden leerse todos los elementos de una matriz sin necesidad de un bucle DO, como en el ejemplo Programa ejemplo_4_1.f90, Sección 4.3.1. En este ejemplo también se presenta la función SUM que suma los elementos de un vector en la aplicación presentada, aunque tiene una aplicación más general.
También es posible referirnos a una sección de una matriz, por ejemplo, usando las matrices definidas arriba podemos hacer
V1(1:10) = 0.5 B (1,1:4) = 100.0
En el primer caso se hacen iguales a 0.5 los diez primeros elementos de V1, mientras que en el segundo se hacen iguales a 100.0 los elementos de la primer fila de A. Puede verse una aplicación de este punto en el ejemplo Programa ejemplo_4_1.f90, Sección 4.3.1.
La forma más general como se define una sección de un arreglo de datos es como liminf:limsup:step: la sección comienza con el índice liminf, termina en limsup y step es el incremento en la variable que marca el índice. Cuando step no está presente, como en los casos anteriores, toma por defecto el valor 1. Algunos ejemplos:
V1(:) ! todo el vector V1(3:10) ! elementos V1(3), V1(4), ... , V1(10) V1(3:10:1) ! "" "" "" "" V1(3:10:2) ! "" V1(3), V1(5), ... , V1(9) V1(m:n) ! elementos V1(m), V1(m+1), ... , V1(n) V1(9:4:-2) ! "" V1(9), V1(7), V1(5) V1(m:n:-k) ! elementos V1(m), V1(m-k), ... , V1(n) V1(::2) ! "" V1(1), V1(3), ... , V1(21) V1(m:m) ! Arreglo 1x1 V1(m) ! Escalar
Es importante diferenciar los dos últimos casos.
Al asignar valores a un arreglo puede utilizarse una máscara lógica, haciendo uso de la orden WHERE. El uso de una máscara lógica permite seleccionar los elementos del arreglo sobre los que se llevará a cabo una operación. Si, por ejemplo, queremos calcular la raíz cuadrada de los elementos de un arreglo real llamado data_mat y almacenarlos en el arreglo sq_data_mat, debemos evitar tomar raíces cuadradas de números negativos. Para ello podemos usar una combinación de bucles y condicionales
DO j_col = 1, dim_2 DO i_row = 1, dim_1 IF ( data_mat(i_row, j_col) >= 0.0 ) THEN sq_data_mat(i_row, j_col) = SQRT( data_mat(i_row, j_col) ) ELSE sq_data_mat(i_row, j_col) = -99999.0 ENDIF ENDDO ENDDO
El uso de WHERE simplifica esta tarea. La forma general de esta orden es
[name:] WHERE (mask_expr_1) .... Array assignment block 1 .... ELSEWHERE (mask_expr_2) [name] .... Array assignment block 2 .... ELSEWHERE .... Array assignment block 3 .... ENDWHERE [name]
Donde mask_expr_1 y mask_expr_2 son arreglos lógicos conformables con la matriz que se asigna. El ejemplo anterior se simplifica usando WHERE
WHERE ( data_mat >= 0.0 ) sq_data_mat = SQRT( data_mat ) ELSEWHERE sq_data_mat = -99999.0 ENDWHERE
Estos puntos se tratan en los diferentes ejemplos proporcionados. En el
ejemplo Programa ejemplo_4_3.f90, Sección 4.3.3 se
puede ver como se inicializan vectores y para matrices. En este último caso
haciendo uso de la orden RESHAPE. Este ejemplo presenta también
las funciones Fortran
DOT_PRODUCT (producto escalar)
y MATMUL (multiplicación de matrices).
En el ejemplo Programa ejemplo_4_4.f90, Sección 4.3.4 se presenta como puede asignarse una matrix usando WHERE, y una "máscara" lógica.
Como se muestra en el ejemplo Programa ejemplo_4_5.f90, Sección 4.3.5 es importante no confundir los resultados esperados al vectorizar un programa eliminando los bucles DO presentes en él.
En el ejemplo Programa ejemplo_4_6.f90, Sección 4.3.6 vemos como usar la orden RESHAPE en la definición de una matriz y como acceder a diferentes partes de la misma.
PROGRAM ej_4_1 ! ! DEFINICION DE VARIABLES IMPLICIT NONE REAL :: Total=0.0, Promedio=0.0 REAL , DIMENSION(:), ALLOCATABLE :: t_trab ! Factor que corrige el tiempo trabajado los dos últimos días REAL :: Fac_correc=1.05 INTEGER :: dia, num_dias ! PRINT *,' Introduzca el no. de dias para los que se va ' PRINT *,' a calcular el promedio de horas y minutos trabajados.' READ(*,*), num_dias ! Dimensiona dinámicamente la matriz ALLOCATE(t_trab(1:num_dias)) ! PRINT *,' Introduzca las horas trabajadas' PRINT *,' por dia en ', num_dias, 'dias.' ! Lectura de datos READ(*,*), t_trab ! t_trab(num_dias-1:num_dias) = Fac_correc*t_trab(num_dias-1:num_dias) ! ! Total = SUM(t_trab) ! Promedio = Total / num_dias ! PRINT *,' Horas de trabajo en ',num_dias, ' dias : ' PRINT *, Promedio ! END PROGRAM ej_4_1
PROGRAM EJEMPLO_4_2 ! ! Program to characterize an array making use of inquiry functions ! IMPLICIT NONE ! REAL, DIMENSION(:,:), ALLOCATABLE :: X_grid INTEGER :: Ierr ! ! ALLOCATE(X_grid(-20:20,0:50), STAT = Ierr) IF (Ierr /= 0) THEN STOP 'X_grid allocation failed' ENDIF ! WRITE(*, 100) SHAPE(X_grid) 100 FORMAT(1X, "Shape : ", 7I7) ! WRITE(*, 110) SIZE(X_grid) 110 FORMAT(1X, "Size : ", I7) ! WRITE(*, 120) LBOUND(X_grid) 120 FORMAT(1X, "Lower bounds : ", 7I6) ! WRITE(*, 130) UBOUND(X_grid) 130 FORMAT(1X, "Upper bounds : ", 7I6) ! DEALLOCATE(X_grid, STAT = Ierr) IF (Ierr /= 0) THEN STOP 'X_grid deallocation failed' ENDIF ! END PROGRAM EJEMPLO_4_2
PROGRAM ej_4_3 ! ! DEFINICION DE VARIABLES IMPLICIT NONE REAL, DIMENSION(1:5) :: VA = (/1.2,2.3,3.4,4.5,5.6/), PMAT INTEGER I INTEGER, DIMENSION(1:5) :: VB = (/(2*I,I=1,5)/) REAL :: PE REAL , DIMENSION(1:5,1:5) :: MC REAL , DIMENSION(25) :: VC = & (/ 0.0,0.0,0.0,0.0,1.0,0.5,2.0,3.2,0.0,0.0, & 0.0,0.0,0.0,0.0,11.0,0.5,2.3,3.2,0.0,0.0, & 1.0,3.0,-2.0,-2.0,-0.6 /) ! Producto escalar VA.VB PE = DOT_PRODUCT(VA,VB) ! PRINT *, 'PRODUCTO ESCALAR (VA,VB) = ', PE ! ! Producto de matrices VAxMC ! Haciendo RESHAPE de VC hacemos que sea una matriz 5 x 5 MC = RESHAPE(VC,(/ 5, 5 /)) PMAT = MATMUL(VA,MC) ! PRINT *, 'PRODUCTO VAxMC = ', PMAT(1:5) ! END PROGRAM ej_4_3
PROGRAM long2 IMPLICIT NONE REAL , DIMENSION(-180:180) :: Time=0 INTEGER :: Degree, Strip REAL :: Value CHARACTER (LEN=1), DIMENSION(-180:180) :: LEW=' ' ! DO Degree=-165,165,15 Value=Degree/15 DO Strip=-7,7 Time(Degree+Strip)=Value ENDDO ENDDO ! DO Strip=0,7 Time(-180 + Strip) = -180/15 Time( 180 - Strip) = 180/15 ENDDO ! DO Degree=-180,180 PRINT *,Degree,' ',Time(Degree), 12 + Time(Degree) END DO ! WHERE (Time > 0) LEW='E' ELSEWHERE (Time < 0) LEW='W' ENDWHERE ! PRINT*, LEW ! END PROGRAM long2
PROGRAM ej_4_5 ! ! DEFINICION DE VARIABLES IMPLICIT NONE REAL, DIMENSION(1:7) :: VA = (/1.2,2.3,3.4,4.5,5.6,6.7,7.8/) REAL, DIMENSION(1:7) :: VA1 = 0.0, VA2 = 0.0 INTEGER I ! VA1 = VA VA2 = VA ! DO I = 2, 7 VA1(I) = VA1(I) + VA1(I-1) ENDDO ! VA2(2:7) = VA2(2:7) + VA2(1:6) ! ! The previous two operations with VA1 and VA2 seem that ! should provide the same result. Which is not the case. PRINT*, VA1 PRINT*, VA2 ! ! To obtain the same effect without an explicit DO loop we can do ! the following VA2 = VA VA2(2:7) = (/ (SUM(VA2(1:I)), I = 2,7) /) ! PRINT*, VA1 PRINT*, VA2 END PROGRAM ej_4_5
PROGRAM ej_4_6 ! ! DEFINICION DE VARIABLES IMPLICIT NONE INTEGER, DIMENSION(1:3,1:3) :: A = RESHAPE( (/ 1,2,3,4,5,6,7,8,9 /), (/ 3,3 /) ) ! ! ! 1 4 7 ! A = 2 5 8 ! 3 6 9 ! PRINT*, "Elemento de la matriz", A(2,3) PRINT*, "Submatriz", A(1:2,2:3) PRINT*, "Submatriz", A(::2,::2) PRINT*, "Columna de la matriz", A(:,3) PRINT*, "Fila de la matriz", A(2,:) PRINT*, "Matriz completa", A PRINT*, "Matriz traspuesta", TRANSPOSE(A) END PROGRAM ej_4_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