práctica 4 representación del conjunto de mandelbrot · práctica 4: representación del conjunto...

22
ETSISI - UPM Procesamiento Paralelo Curso 19/20 31 de Octubre 2019 Práctica 4 Representación del Conjunto de Mandelbrot

Upload: others

Post on 30-Apr-2020

3 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

31 de Octubre 2019

Práctica 4

Representación del Conjunto de Mandelbrot

Page 2: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 1

ÍNDICE

1 Objetivos ......................................................................................................................................................... 2

2 El entorno gráfico básico ................................................................................................................................. 2

3 Descripción del fractal del conjunto de Mandelbrot........................................................................................ 4

4 Representación gráfica del fractal ................................................................................................................... 4

5 Algoritmo secuencial (mandelsec) .................................................................................................................. 7

6 El entorno gráfico completo (mandelsecBis) .................................................................................................10

7 Algoritmo paralelo (mandelpar) .....................................................................................................................14

8 Tablas de tiempos ...........................................................................................................................................17

9 Anexos ...........................................................................................................................................................18 9.1 Módulo mapapixel.h completo .............................................................................................................. 18 9.2 Módulo plano2D.c ................................................................................................................................. 20 9.3 Módulo mandelbrot.c ............................................................................................................................ 21

Page 3: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 2

1 Objetivos

• Familiarizarse con un entorno de representación gráfica basado en GTK sobre entorno XWindow.

• Explorar el conjunto de Mandelbrot mediante un programa secuencial ya escrito, para constatar cómo afecta la precisión (número de colores) y la zona de representación, al tiempo total de cálculo.

• Programar una versión paralela donde se aborde el problema del reparto de trabajo.

2 El entorno gráfico básico

Para poder dibujar en pantalla, se suministra un módulo “mapapixel.c” con su correspondiente parte de definición “mapapixel.h”, cuyas funciones más básicas son las siguientes:

typedef void (*mapiFuncionAccion) (void); typedef void (*mapiFuncionClick) (short columna, short fila, int botonIzquierdo); typedef void (*mapiFuncionCierre) (void); int mapiInicializar (short filas, short columnas, mapiFuncionAccion fAccion, mapiFuncionClick fClick, mapiFuncionCierre fCierre); void mapiDibujarPunto (short fila, short columna, int color); void mapiDibujarLinea (short fila1, short columna1, short fila2, short columna2, int color); void mapiDibujarRectangulo (short fila, short columna, short ancho, short largo, int color); La función mapiInicializar, representará en pantalla una ventana como la siguiente:

Page 4: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 3

La ventana tendrá un área de dibujo de tantas “filas” y “columnas” como se haya indicado en la llamada. Cuando se pulse en el botón de “Acción” que figura en la barra inferior, se invocará la función de usuario que se pasó como parámetro “fAccion”. Además, al hacer clic con el ratón en el área de dibujo, se invocará la función de usuario que se pasó como parámetro “fClick”, que recibirá como parámetros la fila y columna donde se hizo clic, así como si se pulsó el botón izquierdo o el derecho. Cuando se cierre la ventana, se invocará la función de usuario que se pasó como parámetro fCierre.

Un programa que hace uso de este interfaz es “dibLinRec.c”, cuyo código es el siguiente: /* dibLinRec.c: Ejemplo de dibujo de lineas y rectangulos. */ #include "mapapixel.h" static short fila1=0, columna1=0; static int color = 255; /*------------------------------------------------------------------*/ static void dibujar(){ mapiDibujarRectangulo (fila1, columna1, 100, 100, color); } /*------------------------------------------------------------------*/ static void clickRaton (short fila, short columna, int botonIzquierdo) { if (botonIzquierdo) mapiDibujarLinea (fila1, columna1, fila, columna, color); else { fila1 = fila; columna1 = columna; } } /*------------------------------------------------------------------*/ int main(int argc, char *argv[]) { // Uso: dibLinRec [colorLapiz] if (argc == 2) color = atoi(argv[1]); mapiInicializar (600, 800, dibujar, clickRaton, NULL); return (0); } Este programa representa una ventana de 600 filas por 800 columnas. Cuando se pulsa el botón izquierdo, se representa una línea desde un punto que inicialmente es el (0,0) hasta el lugar donde se realizó la pulsación. Con un clic con el botón derecho, se cambia de punto inicial. Si se pulsa el botón de “Acción”, se dibuja un rectángulo.

Antes de nada, al igual que en las prácticas anteriores, traerse desde el servidor todos los ficheros que residan en el correspondiente directorio del usuario propar00 en el directorio “$HOME/p4”

Generar el ejecutable de dibLinRec.c tecleando: make dibLinRec. Ejecutarle y dibujar algunas rectas y rectángulos para comprobar el buen funcionamiento del entorno gráfico

Page 5: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 4

3 Descripción del fractal del conjunto de Mandelbrot

Los fractales son representaciones gráficas de funciones matemáticas que suelen parecerse a paisajes y formas de la naturaleza, donde pueden observarse muchos ejemplos de estructuras repetitivas que configuran hojas, dunas, etc.

Como el objetivo no es dominar la teoría de fractales, lo que se abordará es la representación parcial de un fractal conocido como conjunto de Mandelbrot. Dicho conjunto está compuesto por los números complejos, c=a+ib, para los que la relación de recurrencia:

Zn+1 = Zn2 + c para n=0,1,2, .....

converge a un número complejo finito, siendo Z0 = 0 la condición inicial.

Se demuestra que si existe un “m” para el cual |Zm| > 2, la serie diverge y “c” no pertenece al conjunto de Mandelbrot. Como el “m”, de existir, podría ser muy grande, la primera aproximación que se hace es llegar como máximo hasta el elemento Zq. Si se alcanza dicho Zq sin que ningún |Zi| sea mayor que 2, se supone que “c” pertenece al conjunto de Mandelbrot.

4 Representación gráfica del fractal

Con el módulo mapapixel.h, ya tenemos la posibilidad de trabajar con una ventana con un área gráfica del tamaño que queramos (supongamos que lo fijamos a 430 filas y 630 columnas, lo que nos da un total de 270.900 pixels).

Si asociamos cada píxel con un punto del plano complejo, podemos evaluar la serie de recurrencia para todos estos puntos y dibujar de un color los pixels que se correspondan con puntos del plano complejo que pertenezcan al conjunto de Mandelbrot y de otro color los demás. Para tener una imagen más vívida, lo que haremos será lo siguiente:

• Elegir el “q” que determina el máximo número de iteraciones

• Si un punto pertenece al conjunto de Mandelbrot, el píxel asociado se pintará de negro (color 0)

• Si el punto no pertenece al conjunto de Mandelbrot, el píxel asociado se pintará con el color “i”, siendo “i” la iteración en la cual |Zi| > 2. En definitiva, el color viene a representar la velocidad con la que diverge la serie

El primer aspecto (determinar el máximo número de iteraciones) tiene relación con el número de colores que nos ofrezca el entorno gráfico (podremos usar menos, pero no más de los que nos dé dicho entorno).

Las funciones del módulo “mapapixel.h” que tienen que ver con la gama de colores que puede manejarse, son las siguientes:

void mapiProfundidadColor (unsigned short profundidad); int mapiNumColoresDefinidos (void);

Page 6: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 5

El modelo de color que se sigue es el denominado RGB, en el que se indica la cantidad de rojo, verde y azul de cada color. En concreto, la gama de colores se define en función de lo que se denomina profundidad. Una profundidad de dos indicará que se utilizan dos bits para expresar tonalidades rojas, otros dos para verdes y otros dos para azules, lo que nos daría un total de 64 colores (26). Por defecto, la profundidad de color es tres, de forma que se dispone de una gama de 512 colores.

Con mapiProfundidadColor podemos fijar una profundidad de color hasta un máximo de 8, y con mapiNumColoresDefinidos podemos conocer el número total de colores que tenemos a nuestra mano con la profundidad actual.

En definitiva, si queremos utilizar 4096 colores, debemos invocar mapiProfundidadColor(4). El color verdadero se obtiene con una profundidad de 8, el que realmente los tengamos o no, dependerá de la tarjeta gráfica del equipo. En nuestro caso, los equipos de prácticas admiten la máxima gama de colores.

Otra cuestión a resolver a la hora de realizar la representación del fractal, es relacionar los pixeles de la pantalla (430*630 = 270.900 en nuestro caso) con los puntos del plano complejo. La idea es limitar la parte del plano complejo que vamos a representar en la pantalla. En el caso de nuestro programa, la representación es la de la figura siguiente:

donde se ha representado los ejes del plano complejo que abarca una ventana de tamaño 2,5 de altura por unos 3,57 de ancho. Por lo tanto, las 430 filas equivalen a 2,5 unidades en el eje Y, y las 630 columnas equivaldrán a 3,57 unidades en el eje X. Para completar la representación, se determina que el centro de la pantalla se encuentra en el punto (X=-0,75 ; Y=0,0) tal y como se indica con el punto gordo central.

630 columnas 3,57

430 filas 2,5

Centro (-0,75 0,0)

Page 7: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 6

Finalmente, puede comprobarse que expresando la altura y el centro de la pantalla, queda completamente determinado qué parte del plano debe representarse en una ventana concreta de tamaño (filas * columnas), ya que el ancho de la ventana puede calcularse como (columnas * altura) / filas.

Todos estos detalles se han plasmado en el módulo “plano2D” cuyas funciones son las siguientes:

void planoMapear (short filas, short columnas, double Cx, double Cy, double laAltura); void planoPixelAPunto (short fila, short columna, double *X, double *Y); Con la función planoMapear, se establece la relación entre la ventana creada con mapiInicializar (en definitiva un número de filas y columnas) y la parte del plano complejo que se representa en la misma (indicando la altura que tiene y las coordenadas en dicho plano del centro de la pantalla). Una vez hecho el mapeo, puede convertirse de pixel a punto con la función planoPixelAPunto.

Con estas ideas, un código que representaría el conjunto de Mandelbrot, tal y como se desarrolló en las clases de teoría, sería el siguiente:

El código concreto del cálculo del color de un pixel, se ha escrito en otro módulo denominado “mandelbrot”, cuyas funciones son las siguientes:

void mandelInit (int maxIteraciones); int mandelbrot (double X, double Y); Con mandelInit fijamos el número máximo de iteraciones de la serie de recurrencia del fractal y con mandelbrot podemos evaluar el color de cualquier pixel de la ventana gráfica, por lo que el código anterior puede escribirse como:

for (f=0; f<FILAS; f++) for (c=0; c<COLUMNAS; c++) { planoPixelAPunto(f, c, &x, &y); //Cacular color del punto(x, y) mapiDibujarPunto(f, c, color); }

for (f=0; f<FILAS; f++) for (c=0; c<COLUMNAS; c++) { planoPixelAPunto (f, c, &x, &y); mapiDibujarPunto (f, c, mandelbrot(x,y)); }

Page 8: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 7

5 Algoritmo secuencial (mandelsec)

Tras los detalles de las secciones anteriores, tenemos tres módulos (mapapixel, plano2D y mandelbrot) que permiten escribir una versión secuencial “mandelsec” siguiendo la descomposición representada en la figura siguiente:

El código definitivo de mandelsec es el siguiente:

//------------------------------------------------------------------+ // PCM. Procesamiento Paralelo Curso 04/05 EUI 04/04/06 | // | // mandelsec.c: Programa que pinta el conjunto de Mandelbrot al | // hacer click con el boton izquierdo o el derecho. | // Haciendo click con el boton izquierdo, se recalcula | // y repinta el dibujo pero aumentando la imagen por | // 2 y centrandola donde se pulso. Si el click se hace | // con el boton derecho, se disminuye por dos. | // Si se pincha el boton de accion, se redibuja el | // conjunto de Mandelbrot sin hacer zoom. | //------------------------------------------------------------------+ #include <assert.h> #include <sys/time.h> #include <stdlib.h> #include <stdio.h> #include "mapapixel.h" #include "plano2D.h" #include "mandelbrot.h" #define TRUE 1 #define FALSE 0

mandelsec

mandelbrot: • init • mandelbrot

plano2D: • mapear • pixelAPunto

mapapixel: • Inicializar • ProfundidadColor • NumColoresDefinidos • DibujarPunto

Page 9: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 8

// Aspectos parametrizables #define FILAS 430 #define COLUMNAS 630 // Coordenadas del mandelbrot inicial static double miAltura = 2.5; static double centroX = -0.75; static double centroY = 0.0; //-------------------------------------------------------------------- static void dibujar() { int fila, columna, color; double X, Y; struct timeval t0, t1, t; assert (gettimeofday(&t0, NULL) == 0); planoMapear (FILAS, COLUMNAS, centroX, centroY, miAltura); for (fila=0; fila<FILAS; fila++) { for (columna=0; columna<COLUMNAS; columna++) { planoPixelAPunto (fila, columna, &X, &Y); color = mandelbrot(X, Y); mapiDibujarPunto (fila, columna, color); } } assert (gettimeofday(&t1, NULL) == 0); timersub(&t1, &t0, &t); printf("Tiempo => %ld:%ld (seg:mseg)\n", t.tv_sec, t.tv_usec/1000); } //-------------------------------------------------------------------- static void clickRaton (short fila, short columna, int botonIzquierdo) { planoPixelAPunto (fila, columna, &centroX, &centroY); if (botonIzquierdo) miAltura = miAltura / 2.0; // Profundizar else miAltura = miAltura * 2.0; // Alejarse dibujar (); } //-------------------------------------------------------------------- int main(int argc, char *argv[]) { int profundidadColor; if (argc == 1) profundidadColor = 3; else if (argc == 2) profundidadColor = atoi(argv[1]); else { printf ("Uso: mandelsec [profundidadColor]\n"); return 0; } mapiProfundidadColor(profundidadColor); mandelInit (mapiNumColoresDefinidos()); mapiInicializar (FILAS, COLUMNAS, dibujar, clickRaton, NULL); return 0; }

Page 10: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 9

Generar el ejecutable de mandelsec.c tecleando: make mandelsec

Intentar ajustar la ventana de comandos “Shell” para que ocupe el cuadrante inferior izquierdo de la pantalla, tal y como se representa al final de esta página, ya que vamos a intentar representar tres veces el fractal con profundidad 2, 3 y 4

Ejecutar el programa mandelsec con profundidad 2 y en background, tecleando:

mandelsec 2 &

Ajustar la ventana gráfica nueva al cuadrante superior izquierdo y pulsar el botón de Acción, aparecerá el fractal. Anotar el tiempo de cálculo en la Tabla-1 de tiempos

Repetir la prueba anterior con profundidad 3 y 4 (cuadrantes superior e inferior derechos respectivamente). Quedará una pantalla como la representada más adelante

Comparar los tiempos que cuesta evaluar el fractal según la profundidad y comprobar la diferencia de nitidez entre las imágenes obtenidas

Explorar el fractal haciendo zoom en las tres ventanas (pulsando el botón izquierdo del ratón) por la zona marcada como “Punto de Zoom” y seguir luego haciendo zoom más o menos en el centro de la pantalla y observar qué sucede

Punto de Zoom

Page 11: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 10

6 El entorno gráfico completo (mandelsecBis)

El entorno gráfico soportado por el módulo “mapapixel”, también permite manipular imágenes en memoria (se denominarán mapas de bits) que pueden salvarse en disco y leerse posteriormente de disco. Estos mapas de bits pueden manipularse con color tipo RGB como el ya mencionado, o como una imagen en escala de grises con 256 tonalidades que van desde el valor 0 que sería el negro, hasta el 255 que sería el blanco.

Todo esto está recogido en la definición de mapapixel.h tal y como se muestra a continuación:

typedef enum { escalaGrises, // Cada pixel un byte. 0 => Negro y 255 => Blanco colorRGB // Cada pixel tres bytes indicando RGB } tipoColor; typedef struct tRGB { unsigned char rojo; // Negro => RGB todos a 0 unsigned char verde; // Blanco => RGB todos a 255 unsigned char azul; } tipoRGB; typedef struct tMapa { tipoColor elColor; short filas; short columnas; char *pixels; // Puntero a un array bidimensional de // dimensiones [filas * columnas ] de un byte // o tres segun sea o no elColor escalaGrises } tipoMapa; void mapiColorRGB (int color, tipoRGB *colorRGB); void mapiCrearMapa (tipoMapa *unMapa); void mapiLeerMapa (char *fichero, tipoMapa *unMapa); void mapiPonerPuntoGris (tipoMapa *unMapa, short fila, short columna, short tonalidad); void mapiPonerPuntoRGB (tipoMapa *unMapa, short fila, short columna, tipoRGB color); void mapiDibujarMapa (tipoMapa *unMapa); void mapiGrabarMapa (char *fichero, tipoMapa *unMapa); La obtención de un mapa de bits en memoria (básicamente el conjunto de pixeles necesarios), puede hacerse con mapiCrearMapa pasando un mapa que tenga definido el tipo de color, las filas y las columnas. Una vez creado, puede generarse una imagen de color poniendo pixeles al color que se desee con la función mapiPonerPuntoRGB y, cuando se acabe de generar, si se desea que aparezca en la ventana gráfica, deberemos invocar mapiDibujarMapa.

Con mapiPonerPuntoGris podemos también generar imágenes en escala de grises, mientras que la función mapiColorRGB nos devuelve un color en formato RGB a partir de un número de color entre 0 y el máximo número de colores actuales.

Page 12: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 11

Para guardar un mapa en disco se utilizará la función mapiGrabarMapa y para poder leerlo mapiLeerMapa. Los formatos en disco son “PGM binario” para imágenes en escala de grises (la extensión del fichero será *.pgm) y “PPM binario” para imágenes en color (la extensión del fichero será *.ppm).

Con esta nueva funcionalidad, podemos escribir un programa (se suministra ya escrito) que lea un mapa de bits y lo represente en pantalla. Este programa se denomina leermapa.c y su código es el siguiente:

/*-----------------------------------------------------------------*/ /* PCM. Procesamiento Paralelo Curso 02/03 EUI 28/04/03 */ /* */ /* leermapa.c: Ejemplo de leer dibujos de ficheros y visualizarlos.*/ /*-----------------------------------------------------------------*/ #include <stdio.h> #include "mapapixel.h" static tipoMapa miMapa; /*------------------------------------------------------------------*/ static void dibujar() { mapiDibujarMapa(&miMapa); } /*------------------------------------------------------------------*/ int main(int argc, char *argv[]) { if (argc == 2) { mapiLeerMapa (argv[1], &miMapa); mapiInicializar (miMapa.filas, miMapa.columnas, dibujar, NULL, NULL); } else printf ("Uso: leermapa fichero\n"); return (0); } Conocido ya el entorno gráfico completo, podemos modificar el programa mandelsec para que cualquier imagen que veamos en pantalla, podamos grabarla en disco y poder leerla y manipularla posteriormente.

Este programa modificado, lo hemos denominado “mandelsecBis” y su código se muestra en las páginas siguientes.

Page 13: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 12

//------------------------------------------------------------------+ // PCM. Procesamiento Paralelo Curso 06/07 EUI 16/04/07 | // | // mandelsecBis.c: Programa que pinta el conjunto de Mandelbrot al | // hacer click con el boton izquierdo o el derecho. | // Haciendo click con el boton izquierdo, se recalcula | // y repinta el dibujo pero aumentando la imagen por | // 2 y centrandola donde se pulso. Si el click se hace | // con el boton derecho, se disminuye por dos. | // Si se pulsa el boton de accion, se recalcula el | // conjunto de Mandelbrot sobre un mapa de bits que | // se graba al fichero "mandelbrot.ppm" y se pinta. | //------------------------------------------------------------------+ #include <assert.h> #include <sys/time.h> #include <stdio.h> #include <stdlib.h> #include "mapapixel.h" #include "plano2D.h" #include "mandelbrot.h" #define TRUE 1 #define FALSE 0 static int dibujado = FALSE; static tipoMapa miMapa; #define FILAS 920 #define COLUMNAS 1270 // Coordenadas del mandelbrot inicial en miniatura static double miAltura = 0.000305; static double centroX = -0.813997; static double centroY = 0.194129; //-------------------------------------------------------------------- static void grabar() { int fila, columna, color; double X, Y; tipoRGB colorRGB; planoMapear (FILAS, COLUMNAS, centroX, centroY, miAltura); for (fila=0; fila<FILAS; fila++) { for (columna=0; columna<COLUMNAS; columna++) { planoPixelAPunto (fila, columna, &X, &Y); color = mandelbrot(X, Y); mapiColorRGB (color, &colorRGB); mapiPonerPuntoRGB (&miMapa, fila, columna, colorRGB); } } mapiDibujarMapa(&miMapa); mapiGrabarMapa("mandelbrot.ppm", &miMapa); }

Page 14: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 13

//-------------------------------------------------------------------- static void dibujar() { int fila, columna, color; double X, Y; struct timeval t0, t1, t; assert (gettimeofday(&t0, NULL) == 0); planoMapear (FILAS, COLUMNAS, centroX, centroY, miAltura); for (fila=0; fila<FILAS; fila++) { for (columna=0; columna<COLUMNAS; columna++) { planoPixelAPunto (fila, columna, &X, &Y); color = mandelbrot(X, Y); mapiDibujarPunto (fila, columna, color); } } assert (gettimeofday(&t1, NULL) == 0); timersub(&t1, &t0, &t); printf("Tiempo => %ld:%ld (seg:mseg)\n", t.tv_sec, t.tv_usec/1000); } //-------------------------------------------------------------------- static void clickRaton (short fila, short columna, int botonIzquierdo) { if (!dibujado) { dibujar(); dibujado = TRUE; } else { planoPixelAPunto (fila, columna, &centroX, &centroY); if (botonIzquierdo) miAltura = miAltura / 2.0; // Profundizar else miAltura = miAltura * 2.0; // Alejarse dibujar (); } } //-------------------------------------------------------------------- int main(int argc, char *argv[]) { int profundidadColor; if (argc == 1) profundidadColor = 3; else if (argc == 2) profundidadColor = atoi(argv[1]); else { printf ("Uso: mandelsecBis [profundidadColor]\n"); return(0); } mapiProfundidadColor(profundidadColor); mandelInit (mapiNumColoresDefinidos()); miMapa.elColor = colorRGB; miMapa.filas = FILAS; miMapa.columnas = COLUMNAS; mapiCrearMapa (&miMapa); mapiInicializar (FILAS, COLUMNAS, grabar, clickRaton, NULL); return 0; }

Page 15: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 14

Generar el ejecutable de mandelsecBis.c tecleando: make mandelsecBis

Lanzar su ejecución: mandelsecBis 4

Forzar su dibujo pulsando con el ratón (da igual botón izquierdo o derecho) en cualquier punto interior de la ventana gráfica en tonalidad gris

Fijarse que el fractal es distinto al de la versión anterior ya que las coordenadas iniciales se han modificado y además la ventana se ha ampliado

Forzar que se grabe esta imagen, para ello, pulsar el botón de Acción

Terminar la ejecución y comprobar que se ha generado el fichero “mandelbrot.ppm” y comprobar que su tamaño es el esperado. Comprobar el contenido de las tres primeras líneas de dicho fichero tecleando: head –3 mandelbrot.ppm

Generar el ejecutable de leermapa.c tecleando: make leermapa

Ejecutar “leermapa” para leer la imagen grabada anteriormente, tecleando: leermapa mandelbrot.ppm

Pulsar Acción y ver la diferencia de tiempos entre calcular la imagen y representarla

Volver a ejecutar “mandelsecBis” y explorar la imagen haciendo zoom (es más rápido si nos alejamos de la zona negra) hasta encontrar una imagen que nos guste y salvarla para posteriormente leerla con “leermapa”

Finalmente, ejecutar “mandelsecBis” con profundidades 2, 3, 4, 5 y 6, y anotar los tiempos de cálculo en la Tabla-2 de tiempos.

7 Algoritmo paralelo (mandelpar)

Implementar una versión paralela siguiendo el modelo de “granja de procesadores”, donde la unidad de trabajo a repartir sea una línea. Se aporta un esqueleto del programa en el fichero “mandelpar.c” cuyo código figura en la página siguiente. En este caso, el proceso maestro (sea el cero) será mejor que se dedique exclusivamente a repartir trabajo, recoger resultados y pintar líneas en la pantalla.

Completar el código de mandelpar.c y generar su ejecutable: make mandelpar. Hasta obtener un programa funcionando correctamente, probar con “profundidad” de 4

Cambiar la “profundidad” a 6 y probar ejecuciones con varios procesos, rellenando la Tabla-3 de tiempos. Las mejores eficiencias se obtienen ejecutando cuatro procesos por nodo: maestro y tres esclavos en el PC de consola, y cuatro esclavos en el resto de PC’s, lo que nos limitará a un máximo de 15 esclavos (suponiendo que trabajaremos como máximo con 4 PC’s). No obstante, puede ensayarse la prueba de poner cuatro esclavos en el nodo del maestro

Comparar la eficiencia obtenida respecto de la que se consiguió en la práctica anterior de cálculo de números primos

Page 16: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 15

// mandelpar.c: Version paralela de mandelsec.c | // E S Q U E L E T O | #include <assert.h> #include <sys/time.h> #include <stdlib.h> #include <stdio.h> #include "mpi.h" #include "mandelbrot.h" #include "plano2D.h" #include "mapapixel.h" #define TRUE 1 #define FALSE 0 #define MAX_ESCLAVOS 19 typedef enum {profundizar, // Asociado a click con boton izquierdo alejarse, // Asociado a click con boton derecho noZoom // Asociado a boton "Accion" } tZoom; #define PROFUNDIDAD_COLOR 4 // Cuando funcione, probar con 5 #define FILAS 920 #define COLUMNAS 1270 //Coordenadas del Mandelbrot inicial en miniatura static double miAltura = 0.000305; static double centroX = -0.813997; static double centroY = 0.194129; static int dibujado = FALSE; // CODIGO DE LOS ESCLAVOS void esclavo(void) { short fila, columna, parametros[3]; tZoom zoom; // Inicializar mapiProfundidadColor (PROFUNDIDAD_COLOR); mandelInit (mapiNumColoresDefinidos()); planoMapear (FILAS, COLUMNAS, centroX, centroY, miAltura); // Recibir parametros del fractal actual: MPI_Bcast (parametros, 3, MPI_SHORT, 0, MPI_COMM_WORLD); do { fila = parametros[0]; columna = parametros[1]; zoom = parametros[2]; // Adaptarse a los parametros del fractal actual // Recibir fila a procesar // Mientras haya filas a procesar // Calcular colores y enviarselos al maestro // Recibir fila a procesar MPI_Bcast (parametros, 3, MPI_SHORT, 0, MPI_COMM_WORLD); } while (parametros[0] != -1); MPI_Finalize(); exit(0); } static int numEsclavos; static short filaCentro=FILAS/2, columnaCentro=COLUMNAS/2; static tZoom zoom = noZoom;

Page 17: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 16

// CODIGO DEL MAESTRO void dibujar(void) { struct timeval t0, t1, t; short parametros[3] ; parametros[0] = fiaCentro; parametros[1] = columnaCentro; parametros[2] = zoom; MPI_Bcast (parametros, 3, MPI_SHORT, 0, MPI_COMM_WORLD); assert (gettimeofday(&t0, NULL) == 0); // Repartir primeras filas // Recibir y volver a enviar trabajo hasta ultima fila dibujada // Enviar indicacion de fin del fractal actual // Informar del tiempo consumido assert (gettimeofday(&t1, NULL) == 0); timersub (&t1, &t0, &t); printf("Tiempo => %ld:%ld(seg:mseg)\n", t.tv_sec, t.tv_usec/1000); } void clickRaton (short fila, short columna, int botonIzquierdo) { if (dibujado) { if (botonIzquierdo) zoom = profundizar; else zoom = alejarse; filaCentro = fila; columnaCentro = columna; } dibujar (); dibujado = TRUE; zoom = noZoom; // Para no hacer zoom si se invoca el boton de Accion } void finalizar (void) { short parametros[3]; parametros[0] = -1; // Enviar indicacion de terminar a los esclavos MPI_Bcast (parametros, 3, MPI_SHORT, 0, MPI_COMM_WORLD); MPI_Finalize(); exit(0); } int main( int argc, char *argv[] ) { int yo; setbuf (stdout, NULL); MPI_Init (&argc, &argv); MPI_Comm_size (MPI_COMM_WORLD, &numEsclavos); numEsclavos--; MPI_Comm_rank (MPI_COMM_WORLD, &yo); if (numEsclavos > MAX_ESCLAVOS) { if (yo == 0) printf ("Error: sobrepasado limite de procesos\n"); return 0; } if (yo == 0) { mapiProfundidadColor (PROFUNDIDAD_COLOR); mapiInicializar (FILAS, COLUMNAS, dibujar, clickRaton, finalizar); } else esclavo(); return 0; }

Page 18: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 17

8 Tablas de tiempos

Tabla-1. Tiempos de la versión mandelsec (ventana de 430*630) profundidad Tiempo (seg:mseg)

2

3

4

Tabla-2. Tiempos de la versión mandelsecBis

(ventana de 920*1270) profundidad Tiempo (seg:mseg)

2

3

4

5

6

Tabla-3. Tiempos de la versión mandelpar con profundidad 6

(ventana de 920*1270) Número de esclavos Tiempo (seg:mseg) Eficiencia

2

4

6

8

10

12

14

15

Page 19: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 18

9 Anexos

9.1 Módulo mapapixel.h completo

/*------------------------------------------------------------------*/ /* PCM. Procesamiento Paralelo Curso 03/04 EUI 28/04/04 */ /* */ /* mapapixel.h: Modulo que permite trabajar en modo grafico con GTK */ /*------------------------------------------------------------------*/ #define MAX_COLUMNAS 1280 #define MAX_FILAS 1024 typedef enum { escalaGrises, // Cada pixel un byte. 0 => Negro y 255 => Blanco colorRGB // Cada pixel tres bytes indicando RGB } tipoColor; typedef struct tRGB { unsigned char rojo; // Negro => RGB todos a 0 unsigned char verde; // Blanco => RGB todos a 255 unsigned char azul; } tipoRGB; //------------------------------------------------------------------- // Prototipos de funciones necesarias para inicializar la ventana de | // dibujo. | //------------------------------------------------------------------- typedef void (*mapiFuncionAccion) (void); typedef void (*mapiFuncionClick) (short columna, short fila, int botonIzquierdo); typedef void (*mapiFuncionCierre) (void); //------------------------------------------------------------------- // Inicializar un mapa de pixels supondra la aparicion de una ventana| // con un area grafica de tamanio "filas" * "columnas" donde podra | // dibujarse mediante funciones de dibujar punto, linea, etc. o bien | // representar de golpe una imagen guardada en un mapa en memoria | // mediante la funcion "mapiDibujarMapa". Inicialmente, la ventana | // grafica se mostrara en tonalidad gris. | // | // Para permitir interactuar con la imagen representada, tambien | // puede pasarse una funcion asociada al click del raton de forma | // que se informa de la fila y columna donde se hizo click y si se | // pulso el boton izquierdo del raton o no (el derecho). | // Tambien pueden asociarse funciones al evento de pulsar el boton | // de accion y de cierre de la venta. | //------------------------------------------------------------------- int mapiInicializar (short filas, short columnas, mapiFuncionAccion fAccion, mapiFuncionClick fClick, mapiFuncionCierre fCierre);

Page 20: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 19

//------------------------------------------------------------------- // Puede definirse una gama de colores mediante la profundidad | // (expresada en numero de bits) de cada color RGB. Por ejemplo, si | // se indica profundidad 3, se dispondra de 512 colores. | // Por defecto, la profundidad del color es 8 (color verdadero). | //------------------------------------------------------------------- void mapiProfundidadColor (unsigned short profundidad); int mapiNumColoresDefinidos (void); void mapiColorRGB (int color, tipoRGB *colorRGB); void mapiDibujarPunto (short fila, short columna, int color); void mapiDibujarLinea (short fila1, short columna1, short fila2, short columna2, int color); void mapiDibujarRectangulo (short fila, short columna, short ancho, short largo, int color); //------------------------------------------------------------------- // Para poder leer y grabar imagenes en el sistema de archivos, se | // utilizara una estructura de "tipoMapa". Estas estructuras podran | // manipularse por el usuario y representarse en la ventana grafica. | //------------------------------------------------------------------- typedef struct tMapa { tipoColor elColor; short filas; short columnas; char *pixels; // Puntero a un array bidimensional de // dimensiones [filas * columnas ] de un byte // o tres segun sea o no elColor escalaGrises } tipoMapa; //------------------------------------------------------------------- // Con la funcion siguiente, se obtiene memoria para los pixels del | // mapa pasado como primer parametro y todos los pixels se ponen a | // negro. | //------------------------------------------------------------------- void mapiCrearMapa (tipoMapa *unMapa); //------------------------------------------------------------------- // Con la siguiente funcion, puede leerse una imagen en formato "PGM"| // binario => escalaGrises o formato "PPM" binario => colorRGB | // La lectura de la imagen se encarga de pedir la memoria necesaria, | // pero no se dibuja en la ventana grafica. | //------------------------------------------------------------------- void mapiLeerMapa (char *fichero, tipoMapa *unMapa); //------------------------------------------------------------------- // Las dos funciones siguientes permiten poner un pixel de un mapa al| // valor que se desee. El cambio en la imagen representada en el mapa| // no se visualizara en la ventana grafica hasta que no se invoque la| // representacion del mapa completo. | //------------------------------------------------------------------- void mapiPonerPuntoGris (tipoMapa *unMapa, short fila, short columna, short tonalidad); void mapiPonerPuntoRGB (tipoMapa *unMapa, short fila, short columna, tipoRGB color);

Page 21: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 20

//------------------------------------------------------------------- // Puede dibujarse un mapa en la ventana grafica, pero para ello, | // debe haberse previamente inicializado con las mismas dimensiones | // (filas y columnas). | //------------------------------------------------------------------- void mapiDibujarMapa (tipoMapa *unMapa); //------------------------------------------------------------------- // Para grabar en disco el mapa indicado. | //------------------------------------------------------------------- void mapiGrabarMapa (char *fichero, tipoMapa *unMapa);

9.2 Módulo plano2D.c

/*-----------------------------------------------------------------*/ /* PCM. Arquitecturas Avanzadas Curso 03/04 EUI 27/04/04 */ /* */ /* plano2D.c: Implementacion del modulo que correlaciona ventana */ /* grafica y plano bidimensional y coordenadas carte- */ /* sianas. */ /*-----------------------------------------------------------------*/ #include "plano2D.h" static double planoVx; /* Coordenadas del vertice inferior izquierdo */ static double planoVy; static short planoFILAS; static short planoCOLUMNAS; static double planoALTURA; static double planoANCHURA; static double planoFactorX; static double planoFactorY; /*-----------------------------------------------------------------*/ void planoMapear (short filas, short columnas, double Cx, double Cy, double laAltura) { planoFILAS = filas; planoCOLUMNAS = columnas; planoALTURA = laAltura; planoANCHURA = (planoCOLUMNAS * planoALTURA) / planoFILAS; planoVx = Cx - (planoANCHURA / 2.0); planoVy = Cy - (planoALTURA / 2.0); planoFactorX = planoANCHURA / (double) (planoCOLUMNAS - 1); planoFactorY = planoALTURA / (double) (planoFILAS - 1); } /*-----------------------------------------------------------------*/ void planoPixelAPunto (short fila, short columna, double *X, double *Y) { *X = (planoFactorX * (double) columna) + planoVx; *Y = (planoFactorY * ((double) (planoFILAS - 1) - (double) fila)) + planoVy; }

Page 22: Práctica 4 Representación del Conjunto de Mandelbrot · Práctica 4: Representación del conjunto de Mandelbrot Página - 3 La ventana tendrá un área de dibujo de tantas “filas”

ETSISI - UPM Procesamiento Paralelo Curso 19/20

Práctica 4: Representación del conjunto de Mandelbrot Página - 21

9.3 Módulo mandelbrot.c

/*-----------------------------------------------------------------*/ /* PCM. Arquitecturas Avanzadas Curso 03/04 EUI 27/04/04 */ /* */ /* mandelbrot.c: Implementacion del modulo que calcula el valor de */ /* divergencia del conjunto de mandelbrot para el */ /* pixel (fila, columna). */ /*-----------------------------------------------------------------*/ #include "mandelbrot.h" static int MANDEL_MAX_ITER = 256; void mandelInit (int maxIteraciones) { MANDEL_MAX_ITER = maxIteraciones; } int mandelbrot (double X, double Y) { double pReal = 0.0; // Parte real X double pImag = 0.0; // Parte imaginaria Y double pRealAnt, pImagAnt, distancia; int i = 0; /* Se evalua la formula de Mandelbrot */ do { pRealAnt = pReal; pImagAnt = pImag; pReal = ((pRealAnt*pRealAnt) - (pImagAnt*pImagAnt)) + X; pImag = (2.0 * (pRealAnt*pImagAnt)) + Y; i++; distancia = pReal*pReal + pImag*pImag; } while ((i < MANDEL_MAX_ITER) && (distancia <= 4.0)); if (i == MANDEL_MAX_ITER) return 0; else return i; }