// Programa Maestro - Esclavo // Autor Antonio Carrillo Ledesma // http://www.mmc.igeofcu.unam.mx/acl #include <math.h> #include <stdio.h> #include <stdlib.h> #include "/usr/lib/mpich/include/mpi.h" #include <time.h> // Funcion de Arnold double F(double T,double A,double B); // Calcula la resonancia de algun punto del espacio de parametros int Resonancias(int MaxPer,int Ciclos,int Trans,double A,double B, double Eps,int *Pr,int *Qr); //#define VIS // Programa Maestro-Esclavo int main(int argc, char *argv[]) { int ME_id,MP_np; int ME_P, ME_L, ME_sw; MPI::Init(argc,argv); ME_id = MPI::COMM_WORLD.Get_rank(); MP_np = MPI::COMM_WORLD.Get_size(); // Revisa que pueda arrancar el esquema M-E if (MP_np < 2) { printf("Se necesitan almenos dos procesadores para el esquema M-E\n"); return 1; } // Controlador del esquema M-E if (ME_id == 0) { // Maestro printf("Maestro-Esclavo, Numero de Esclavos %d\n",MP_np-1); ME_P = 1; ME_sw = 1; time_t inicio,final; inicio=time(NULL); double T; for (T = 0.0; T < 1.0; T+=0.0009765625) { // Llena de trabajo a los trabajadores if (ME_P < MP_np) { // Aviso de envio de una nueva tarea al nodo P MPI::COMM_WORLD.Send(&ME_sw, 1, MPI::INT, ME_P,1); // Preparacion para envio de una nueva tarea // Envio de una nueva tarea al nodo P MPI::COMM_WORLD.Send(&T, 1, MPI::DOUBLE, ME_P,0); #ifdef VIS printf("Maestro envio S %d\n",ME_P); #endif ME_P++; } else { // Recibo de terminación de tarea del nodo L MPI::COMM_WORLD.Recv(&ME_L, 1, MPI::INT, MPI_ANY_SOURCE,0); #ifdef VIS printf("Tarea Terminada S%d\n",ME_L); #endif // Aviso de envio de una nueva tarea al nodo L MPI::COMM_WORLD.Send(&ME_sw, 1, MPI::INT, ME_L,1); // Preparacion para envio de una nueva tarea // Envio de una nueva tarea al nodo L MPI::COMM_WORLD.Send(&T, 1, MPI::DOUBLE, ME_L,0); #ifdef VIS printf("Maestro envio S %d\n",ME_L); #endif } } ME_P--; #ifdef VIS printf("Tareas Pendientes %d\n",ME_P); #endif while(ME_P> 0) { // Recibo de terminación de tarea del nodo L MPI::COMM_WORLD.Recv(&ME_L, 1, MPI::INT, MPI_ANY_SOURCE,0); #ifdef VIS printf("Tarea Terminada S%d\n",ME_L); #endif ME_P--; #ifdef VIS printf("Tareas Pendientes %d\n",ME_P); #endif } ME_sw = 0; // Aviso de terminación de tareas al nodo P for (ME_P = 1; ME_P < MP_np; ME_P++) MPI::COMM_WORLD.Send(&ME_sw, 1, MPI::INT, ME_P,1); final=time(NULL); printf("El tiempo empleado fue %lf segundos\n",difftime(final,inicio)); } else { // Esclavos // Recolector de trabajo FILE* datos; char xcad[100]; sprintf(xcad,"DatS%d.dat",ME_id); datos = fopen(xcad,"wt"); int sw; while (1) { double A; // Recibo aviso de envio de una nueva tarea MPI::COMM_WORLD.Recv(&sw, 1, MPI::INT, 0,1); if (!sw) { #ifdef VIS printf("Termina esclavo: %d\n",ME_id); #endif break; } // Recibo una nueva tarea MPI::COMM_WORLD.Recv(&A, 1, MPI::DOUBLE, 0,0); #ifdef VIS printf("Esclavo: %d ---> tarea: %lf\n",ME_id,A); #endif // Procesamiento de la tarea int Pr,Qr; double B; for (B = 0.0; B < 1.0; B+=0.0009765625) { if (Resonancias(100, 100, 50, A, B, 0.1,&Pr,&Qr) ) fprintf(datos,"%lf %lf %d %d\n",A,B,Pr,Qr); } // Avisa la terminacion del trabajo MPI::COMM_WORLD.Send(&ME_id, 1, MPI::INT, 0,0); } fclose(datos); } MPI::Finalize(); return 0; } // Funcion de Arnold double F(double T,double A,double B) { return(T + A + B*sinl(2.0*M_PI*T)); } // Calcula la resonancia de algun punto del espacio de parametros int Resonancias(int MaxPer,int Ciclos,int Trans,double A,double B, double Eps,int *Pr,int *Qr) { /*************************************************************************** * Resonancias calcula la resonancia de algun punto del espacio de * * parametros * * * * Entradas : * * MaxPer : Maximo periodo para buscar * * Ciclos : Numero de ciclos en la busqueda * * Trans : Longitud del transitorio * * A : Valor del parametro A * * B : Valor del parametro B * * Eps : Tolerancia deseada para considerar que una orbita es cerrada* * * * Salidas : La funcion retorna un valor verdadero si fue posible* * calcular la resonancia en algun punto, y en Pr y Qr retorna * * el numero de vueltas y el periodo, respectivamente, de la * * resonancia. * **************************************************************************/ int Found=0; /*** Variable auxiliar para determinar si se encontro alguna resonancia ***/ int I=0; /*** Contador de iteraciones ***/ int J; /*** Contador de iteraciones ***/ double aux; /*** Variable auxiliar para obtener partes fraccionarias ***/ double aux2; /*** Variable auxiliar para obtener partes fraccionarias ***/ double X; /*** Auxiliar para almacenar las iteraciones de la funcion de disparos ***/ double X0; /*** Almacena el primer valor de las iteraciones para buscar las resonancias ***/ int K; /*** Contador de ciclos ***/ X0=random()/2.e09; // Condicion inicial aleatoria do { // Transitorios X0=modf(F(X0,A,B),&aux); I++; } while (I<Trans); K=0; X=X0; do { // Comienza otro ciclo do { // Busca una primera aproximacion I=0; while ((!Found) && (I<MaxPer)) // busca la resonancia { // y halla una primera orbita X=modf(X,&aux); // periodica X=F(X,A,B); Found=((fabs(X0-modf(X,&aux))<Eps) || (fabs(fabs(X0-modf(X,&aux))-1.0)<Eps)); I++; // Almacena el periodo de la orbita en la variable I } if ((I>=MaxPer) && (!Found)) { K++; X0=X; //Transitorio variable si no encontro una orbita periodica } } while ((!Found) && (K<Ciclos)); if (Found) { // Comienza comprobacion de la resonancia hallada Found=0; if ((I>0) && (I<MaxPer)) { X=modf(X,&aux); X0=X; aux=0.0; for (J=0; J<I; J++) { //Ciclo de check X=modf(X,&aux); X=F(X,A,B)+aux; } Found=((fabs(X0-modf(X,&aux2))<=Eps) || (fabs(fabsl(X0-modf(X,&aux2))-1.0)<=Eps)); if (Found) { // Se encontro resonancia y paso el check *Pr= (int) aux; // Asigna numero de vueltas (envolvencia). *Qr=I; // Asigna periodo almacenado (resonancia). return(Found); } } } X0=modf(X,&aux); // Si no detecto periodicidad toma otro punto X=X0; // mas avanzado de una probable orbita y lo // utiliza al volver a entrar al loop. K++; } while ((!Found) && (K<Ciclos) && (I<MaxPer) && (J<MaxPer)); if (!Found) { // No encontro resonancia en el punto *Pr=-1; *Qr=-1; } return(Found); }