4. PRUEBAS. 101
4.1. INTRODUCCIÓN. En este capítulo se presentan dos secciones claramente diferenciadas. La primera es una descripción breve de algunos de los ficheros de ejemplo de vectores y matrices, incluidos con la instalación de PETSc. Este apartado se ha realizado porque existen ciertas rutinas de interés, que vistas en un contexto de código de aplicación cobran bastante sentido. La segunda parte del capítulo, explica lo que se ha realizado en la fase del proyecto de creación de aplicaciones de prueba. También se detalla todo brevemente, ya que los códigos de las aplicaciones, que se incluyen en el Anexo II, se encuentran suficientemente comentados. 102
4.2. EJEMPLOS DE LA PETSC. 4.2.1. VECTORES. Sólo describiremos aquellos ejemplos escritos en C, los ejemplos en Fortran son análogos. Simplemente, iremos nombrando los ficheros y describiendo un poco las características principales. Todos los ficheros a los que se hace referencia se encuentran dentro del directorio de vectores. ex1.c: utilización de la rutina PetscRealPart, para números complejos. ex1e.c: mismo ejemplo al anterior, sólo que no se utiliza la macro de chequeo CHKERRQ, sino que se utiliza un método basado en los caracteres _ y que se añaden a los nombres de las rutinas para realizar la comprobación de errores. ex2.c: empleo de la variable rank (número de proceso), obtenida mediante la rutina MPI_Comm_rank. Creación de un vector paralelo. ex3.c: diseño de un vector paralelo, y utilización de objetos visualizadores, para ver el contenido de las componentes de un vector. ex5.c: registro de eventos y rutinas PetscSleep (para que un proceso aguarde un cierto tiempo) y PetscBarrier (equivalente a la rutina MPI_Barrier, de MPI). ex6.c: E/S a un fichero y creación de un vector a partir del fichero creado. ex7.c: llamada a rutina de cálculo escrita en Fortran desde C. En el ejemplo ex7f.f es al contrario. ex8.c: utilización de la ordenación local para insertar valores dentro de un vector paralelo. ex9.c: manejo de las rutinas PetscSynchronizedPrintf y PetscSynchronizedFlush. Ejemplo de utilización de las rutinas que trabajan con valores ghost. ex11.c: uso de las rutinas VecStrideNorm y VecSetBlockSize ex12.c: ejemplo de rutinas que realizan operaciones de dispersión y recolección de valores de vectores. ex13.c: rutinas PetscBarrier y PetscObjetcPublish. ex15.c: registro de eventos e interacción de PETSc con el programa Mathematica. ex16.c: dispersiones y recolecciones de valores de vectores que están divididos en bloques. ex17.c: polimorfismo (para C++). 103
4.2.2. MATRICES. Seguiremos el mismo esquema que para el caso de vectores. Los ficheros a los que se hace referencia se encuentran almacenados en el subdirectorio de matrices de los paquetes de PETSc. ex1.c: lectura de una matriz y un vector desde un fichero y posterior reordenación. La opción -log_summary especificada en línea de comandos al ejecutar una aplicación paralela, da información sobre los tiempos de ejecución de dicha aplicación. Si antes de realizar la carga en memoria de un sistema grande, realizamos una precarga de un sistema menor, PETSc es capaz de calcular con más precisión los tiempos mencionados. Para realizar la precarga y carga de ambos sistemas, PETSc proporciona ciertas rutinas, algunas de las cuales se presentan en este ejemplo. ex2.c: manejo de matrices densas secuenciales y multiplicación de una matriz por un vector de forma directa y por subbloques. ex4.c: lectura de una matriz U y una matriz V desde un fichero y posterior realización de la operación y = V U T x. ex5.c: en este ejemplo, cada proceso abre su propio fichero y lee su porción de una matriz paralela. ex6.c: polimorfismo (para C++). 104
4.3. APLICACIONES CREADAS PARA EL PROYECTO. A la hora de escribir código de aplicaciones paralelas, se ha empleado Fortran como lenguaje principal, debido a requerimientos del proyecto. No obstante, se ha realizado una aplicación en C, cuyo código fuente se encuentra en el fichero prueba1.c. Esta aplicación crea un vector x y una matriz A. Posteriormente se insertan valores en ambos objetos mediante ordenación local y global, respectivamente. Por último se realiza el producto matriz por vector y se presenta el vector resultado por pantalla. Es un ejemplo de manejo de rutinas sencillas de PETSc, aunque es bastante didáctico para observar algunas peculiaridades de la programación orientada a objetos que utiliza la librería paralela. El resto de pruebas se han realizado en Fortran. Haremos una breve descripción de cada una de las aplicaciones paralelas creadas. Realmente, cada aplicación se apoya en los conocimientos de la creada con anterioridad, de forma que se va aumentando la complejidad. Todas las pruebas aquí presentadas se encuentran en el directorio unidadcd:/pruebas/pruebas-petsc. prueba1.f90: Esta aplicación realiza lo mismo que prueba1.c, simplemente se ha mapeado de C a Fortran. La gran ventaja de PETSc es que la interfaz de las rutinas que proporciona es prácticamente la misma para C que para Fortran. struct.f90: El fin de esta aplicación es crear una matriz con una estructura determinada (bloques bien definidos). Una vez creada la matriz e insertados los valores en las posiciones requeridas (los valores son generados aleatoriamente), se multiplica por un vector cuyas componentes valen la unidad. Por último, se presenta el resultado de la operación por pantalla. KSPstruct.F90: La matriz que se utiliza es la misma que la de la prueba anterior, sólo que ahora no se realiza una simple multiplicación matriz por vector. En vez de eso, primero se realiza el producto A x 1, obteniendo el vector b. Posteriormente, se resuelve el sistema A x 2 = b mediante un solver lineal dado por un objeto KSP, y esto da lugar al vector solución x 2. Finalmente, se calcula la norma del vector de error (diferencia entre x 1 y x 2 ) para comprobar la fidelidad del resultado dado por el solver de KSP. KSPstruct_Luis.F90: Esta aplicación es exactamente igual a la anterior, solo que los bloques de la matriz no contienen valores aleatorios, sino que son determinados a conciencia, de manera que se observe el comportamiento de solver lineal ante valores aleatorios y deterministas. Tanto esta aplicación como la precedente, presentan una norma 2 del vector de error del orden de 10-7, que es un buen resultado. diag_dom.f90: El código sigue el mismo esquema que el anterior, con la diferencia de que ahora la matriz del sistema es llena (todos los elementos son números aleatorios) y los elementos de la diagonal están multiplicados por N 2, la dimensión de la matriz al cuadrado (diagonal dominante). diag_domn.f90: En esta aplicación, la matriz se dispone en forma de tablero de ajedrez, es decir, por bloques de ceros y de elementos llenos alternados unos con 105
otros. Los bloques llenos contienen números aleatorios, y los bloques de la diagonal están multiplicados por N, la dimensión de la matriz. Es interesante ver la parte del código donde se realiza el prealojamiento de espacio en memoria para la matriz a la hora de crearla. Dentro del subdirectorio pruebas_fortran/outs se encuentran algunos resultados de la ejecución de las aplicaciones diag_dom y diag_domn. En concreto, el fichero DIAG_DOM_30e3.txt es el resultado de la ejecución de diag_dom para una matriz de 30.000 x 30.000 elementos. La ejecución de esta aplicación da una norma del vector de error de 0.6608E-06, con sólo dos iteraciones del algoritmo de GMRES, que es un resultado esperado sabiendo que la diagonal de la matriz está multiplicada por N 2 (matriz con diagonal muy dominante, el GMRES funciona bien para este tipo de sistemas). El resto de archivos corresponden a ejecuciones de la aplicación diag_domn, sistema del tablero de ajedrez. Sin embargo, en este caso, los resultados no son tan buenos, debido a que el GMRES necesita que la matriz tenga unas ciertas características, como, por ejemplo, la disposición de los bloques de ceros en la matriz. Veamos algunas de las conclusiones de estas pruebas. La tabla 10 refleja los resultados para la ejecución de la aplicación diag_domn, para una matriz de 10.000 x 10.000 elementos, sin precondicionador. Num. Máx Iteraciones Num.vectores subespacio Krylov Tiempo ejecución Norma 2 vector error 10.000 30 8.6 min. 11,07 10.000 60 8.65 min. 11,04 10.000 100 8.61 min. 11,00 20.000 30 17.33 min. 11,07 20.000 60 17.08 min. 11,04 Tabla 10. Matriz 10.000 x 10.000 (sin Precondicionador). Se puede observar, que con 60 vectores para el parámetro de restart del GMRES, al aumentar el número de iteraciones, la norma del vector de error (norma 2) no varía. En este caso, aumentar el número de vectores para la base utilizada en el proceso de ortogonalización no influye. Doblar el número de iteraciones dobla el tiempo de resolución y no reduce el error. Es importante estudiar bien los parámetros de tolerancia absoluta, relativa y de divergencia del GMRES, para así lograr la convergencia del algoritmo. Para el caso de una matriz de 40.000 x 40.000 elementos, la tabla 11 muestra los resultados. Num. Máx Iteraciones Num.vectores subespacio Krylov Tiempo ejecución Norma 2 vector error 10.000 30 2.20 horas 118,30 20.000 30 4.30 horas 11,30 Tabla 11. Matriz 40.000 x 40.000 (sin Precondicionador). El número de iteraciones afecta a la norma del vector de error si la dimensión de la matriz es grande (como es este caso). Ahora, doblar el número de iteraciones dobla el tiempo de resolución y sí reduce el error, además en un orden de magnitud. 106
Para el sistema con matriz en disposición de tablero de ajedrez, en ningún caso se ha llegado a la convergencia, el GMRES siempre ha agotado el número máximo de iteraciones. No obstante, con las pruebas realizadas se demuestra el correcto funcionamiento del cluster y de las aplicaciones paralelas realizadas con la librería PETSc. El asunto de la convergencia del GMRES es un tema que habría que abordar tras realizar un estudio de la forma de operar del algoritmo, lo que llevaría a un correcto ajuste de los parámetros de tolerancia y a un diseño adecuado de la matriz del sistema a resolver. 107