diff --git a/drop_billiard.c b/drop_billiard.c index ab951b0..a45d841 100644 --- a/drop_billiard.c +++ b/drop_billiard.c @@ -42,6 +42,8 @@ // #define YMIN -1.125 // #define YMAX 1.125 /* y interval for 9/16 aspect ratio */ +#define SCALING_FACTOR 1.0 /* scaling factor of drawing, needed for flower billiards, otherwise set to 1.0 */ + /* Choice of the billiard table */ #define B_DOMAIN 9 /* choice of domain shape */ @@ -55,6 +57,8 @@ #define D_ANNULUS 7 /* annulus */ #define D_POLYGON 8 /* polygon */ #define D_REULEAUX 9 /* Reuleaux and star shapes */ +#define D_FLOWER 10 /* Bunimovich flower */ +#define D_ALT_REU 11 /* alternating between star and Reuleaux */ // #define LAMBDA 1.0 /* parameter controlling shape of billiard */ #define LAMBDA 1.124950941 /* sin(36°)/sin(31.5°) for 5-star shape with 45° angles */ @@ -66,6 +70,8 @@ #define FOCI 1 /* set to 1 to draw focal points of ellipse */ #define NPOLY 5 /* number of sides of polygon */ #define APOLY -1.0 /* angle by which to turn polygon, in units of Pi/2 */ +#define DRAW_BILLIARD 1 /* set to 1 to draw billiard */ +#define DRAW_CONSTRUCTION_LINES 1 /* set to 1 to draw additional construction lines for billiard */ #define RESAMPLE 0 /* set to 1 if particles should be added when dispersion too large */ diff --git a/heat.c b/heat.c new file mode 100644 index 0000000..375af8b --- /dev/null +++ b/heat.c @@ -0,0 +1,812 @@ +/*********************************************************************************/ +/* */ +/* Animation of heat equation in a planar domain */ +/* */ +/* N. Berglund, May 2021 */ +/* */ +/* Feel free to reuse, but if doing so it would be nice to drop a */ +/* line to nils.berglund@univ-orleans.fr - Thanks! */ +/* */ +/* compile with */ +/* gcc -o heat heat.c */ +/* -L/usr/X11R6/lib -ltiff -lm -lGL -lGLU -lX11 -lXmu -lglut -O3 -fopenmp */ +/* */ +/* To make a video, set MOVIE to 1 and create subfolder tif_heat */ +/* It may be possible to increase parameter PAUSE */ +/* */ +/* create movie using */ +/* ffmpeg -i wave.%05d.tif -vcodec libx264 wave.mp4 */ +/* */ +/*********************************************************************************/ + +/*********************************************************************************/ +/* */ +/* NB: The algorithm used to simulate the wave equation is highly paralellizable */ +/* One could make it much faster by using a GPU */ +/* */ +/*********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include /* Sam Leffler's libtiff library. */ +#include + +#define MOVIE 0 /* set to 1 to generate movie */ + +/* General geometrical parameters */ + +#define WINWIDTH 1280 /* window width */ +#define WINHEIGHT 720 /* window height */ + +#define NX 1280 /* number of grid points on x axis */ +#define NY 720 /* number of grid points on y axis */ +// #define NX 640 /* number of grid points on x axis */ +// #define NY 360 /* number of grid points on y axis */ + +/* setting NX to WINWIDTH and NY to WINHEIGHT increases resolution */ +/* but will multiply run time by 4 */ + +#define XMIN -2.0 +#define XMAX 2.0 /* x interval */ +// #define XMIN -1.5 +// #define XMAX 2.5 /* x interval */ +#define YMIN -1.125 +#define YMAX 1.125 /* y interval for 9/16 aspect ratio */ + +#define JULIA_SCALE 1.1 /* scaling for Julia sets */ +// #define JULIA_SCALE 0.8 /* scaling for Julia sets */ + +/* Choice of the billiard table */ + +#define B_DOMAIN 25 /* choice of domain shape */ + +#define D_RECTANGLE 0 /* rectangular domain */ +#define D_ELLIPSE 1 /* elliptical domain */ +#define D_STADIUM 2 /* stadium-shaped domain */ +#define D_SINAI 3 /* Sinai billiard */ +#define D_DIAMOND 4 /* diamond-shaped billiard */ +#define D_TRIANGLE 5 /* triangular billiard */ +#define D_FLAT 6 /* flat interface */ +#define D_ANNULUS 7 /* annulus */ +#define D_POLYGON 8 /* polygon */ +#define D_YOUNG 9 /* Young diffraction slits */ +#define D_GRATING 10 /* diffraction grating */ +#define D_EHRENFEST 11 /* Ehrenfest urn type geometry */ + +#define D_MENGER 15 /* Menger-Sierpinski carpet */ +#define D_JULIA_INT 16 /* interior of Julia set */ + +/* Billiard tables for heat equation */ + +#define D_ANNULUS_HEATED 21 /* annulus with different temperatures */ +#define D_MENGER_HEATED 22 /* Menger gasket with different temperatures */ +#define D_MENGER_H_OPEN 23 /* Menger gasket with different temperatures and larger domain */ +#define D_MANDELBROT 24 /* Mandelbrot set */ +#define D_JULIA 25 /* Julia set */ +#define D_MANDELBROT_CIRCLE 26 /* Mandelbrot set with circular conductor */ + +#define LAMBDA 0.7 /* parameter controlling the dimensions of domain */ +#define MU 0.1 /* parameter controlling the dimensions of domain */ +#define NPOLY 6 /* number of sides of polygon */ +#define APOLY 1.0 /* angle by which to turn polygon, in units of Pi/2 */ +#define MDEPTH 2 /* depth of computation of Menger gasket */ +#define MRATIO 5 /* ratio defining Menger gasket */ +#define MANDELLEVEL 1000 /* iteration level for Mandelbrot set */ +#define MANDELLIMIT 10.0 /* limit value for approximation of Mandelbrot set */ +#define FOCI 1 /* set to 1 to draw focal points of ellipse */ + +/* You can add more billiard tables by adapting the functions */ +/* xy_in_billiard and draw_billiard in sub_wave.c */ + +/* Physical patameters of wave equation */ + +// #define DT 0.00001 +#define DT 0.000004 +// #define DT 0.000002 +// #define DT 0.00000002 +// #define DT 0.000000005 +#define VISCOSITY 10.0 +#define T_OUT 2.0 /* outside temperature */ +#define T_IN 0.0 /* inside temperature */ +// #define T_OUT 0.0 /* outside temperature */ +// #define T_IN 2.0 /* inside temperature */ +#define SPEED 0.0 /* speed of drift to the right */ + +/* Boundary conditions */ + +#define B_COND 0 + +#define BC_DIRICHLET 0 /* Dirichlet boundary conditions */ +#define BC_PERIODIC 1 /* periodic boundary conditions */ +#define BC_ABSORBING 2 /* absorbing boundary conditions (beta version) */ + +/* Parameters for length and speed of simulation */ + +#define NSTEPS 4500 /* number of frames of movie */ +#define NVID 50 /* number of iterations between images displayed on screen */ +// #define NVID 100 /* number of iterations between images displayed on screen */ +#define NSEG 100 /* number of segments of boundary */ + +#define PAUSE 100 /* number of frames after which to pause */ +#define PSLEEP 1 /* sleep time during pause */ +#define SLEEP1 2 /* initial sleeping time */ +#define SLEEP2 1 /* final sleeping time */ + +/* For debugging purposes only */ +#define FLOOR 0 /* set to 1 to limit wave amplitude to VMAX */ +#define VMAX 10.0 /* max value of wave amplitude */ + +/* Field representation */ + +#define FIELD_REP 0 + +#define F_INTENSITY 0 /* color represents intensity */ +#define F_GRADIENT 1 /* color represents norm of gradient */ + +#define DRAW_FIELD_LINES 1 /* set to 1 to draw field lines */ +#define FIELD_LINE_WIDTH 1 /* width of field lines */ +#define N_FIELD_LINES 200 /* number of field lines */ +#define FIELD_LINE_FACTOR 100 /* factor controlling precision when computing origin of field lines */ + +/* Color schemes */ + +#define BLACK 1 /* black background */ + +#define COLOR_SCHEME 1 /* choice of color scheme */ + +#define C_LUM 0 /* color scheme modifies luminosity (with slow drift of hue) */ +#define C_HUE 1 /* color scheme modifies hue */ +#define C_PHASE 2 /* color scheme shows phase */ + +#define SCALE 0 /* set to 1 to adjust color scheme to variance of field */ +// #define SLOPE 0.1 /* sensitivity of color on wave amplitude */ +#define SLOPE 0.3 /* sensitivity of color on wave amplitude */ +#define ATTENUATION 0.0 /* exponential attenuation coefficient of contrast with time */ + +#define COLORHUE 260 /* initial hue of water color for scheme C_LUM */ +#define COLORDRIFT 0.0 /* how much the color hue drifts during the whole simulation */ +#define LUMMEAN 0.5 /* amplitude of luminosity variation for scheme C_LUM */ +#define LUMAMP 0.3 /* amplitude of luminosity variation for scheme C_LUM */ +#define HUEMEAN 280.0 /* mean value of hue for color scheme C_HUE */ +#define HUEAMP -110.0 /* amplitude of variation of hue for color scheme C_HUE */ +// #define HUEMEAN 270.0 /* mean value of hue for color scheme C_HUE */ +// #define HUEAMP -130.0 /* amplitude of variation of hue for color scheme C_HUE */ + +/* Basic math */ + +#define PI 3.141592654 +#define DPI 6.283185307 +#define PID 1.570796327 + +double julia_x = 0.0, julia_y = 0.0; /* parameters for Julia sets */ + + +#include "sub_wave.c" + +double courant2; /* Courant parameter squared */ +double dx2; /* spatial step size squared */ +double intstep; /* integration step */ +double intstep1; /* integration step used in absorbing boundary conditions */ + + + +void init_gaussian(x, y, mean, amplitude, scalex, phi, xy_in) +/* initialise field with gaussian at position (x,y) */ + double x, y, mean, amplitude, scalex, *phi[NX]; + short int * xy_in[NX]; + +{ + int i, j, in; + double xy[2], dist2, module, phase, scale2; + + scale2 = scalex*scalex; + printf("Initialising field\n"); + for (i=0; i= 2) phi[i][j] = T_IN*pow(0.75, (double)(in-2)); +// else if (in >= 2) phi[i][j] = T_IN*pow(1.0 - 0.5*(double)(in-2), (double)(in-2)); +// else if (in >= 2) phi[i][j] = T_IN*(1.0 - (double)(in-2)/((double)MDEPTH))*(1.0 - (double)(in-2)/((double)MDEPTH)); + else phi[i][j] = T_OUT; + } +} + +void init_julia_set(phi, xy_in) +/* change Julia set boundary condition */ + double *phi[NX]; + short int * xy_in[NX]; + +{ + int i, j, in; + double xy[2], dist2, module, phase, scale2; + +// printf("Changing Julia set\n"); + for (i=0; i= 2) phi[i][j] = T_IN; + } +} + + +/*********************/ +/* animation part */ +/*********************/ + + +void compute_gradient(phi, nablax, nablay) +/* compute the gradient of the field */ +double *phi[NX], *nablax[NX], *nablay[NX]; +{ + int i, j, iplus, iminus, jplus, jminus; + double dx; + + dx = (XMAX-XMIN)/((double)NX); + + for (i=0; i NX-1) ij[0] = NX-1; + if (ij[1] < 0) ij[1] = 0; + if (ij[1] > NY-1) ij[1] = NY-1; + + nabx = nablax[ij[0]][ij[1]]; + naby = nablay[ij[0]][ij[1]]; + + norm2 = nabx*nabx + naby*naby; + + if (norm2 > 1.0e-14) + { + /* avoid too large step size */ + if (norm2 < 1.0e-9) norm2 = 1.0e-9; + norm = sqrt(norm2); + x1 = x1 + delta*nabx/norm; + y1 = y1 + delta*naby/norm; + } + else + { + cont = 0; +// nablax[ij[0]][ij[1]] = 0.0; +// nablay[ij[0]][ij[1]] = 0.0; + } + + if (!xy_in[ij[0]][ij[1]]) cont = 0; + + /* stop if the boundary is hit */ +// if (xy_in[ij[0]][ij[1]] != 1) cont = 0; + +// printf("x1 = %.3lg \t y1 = %.3lg \n", x1, y1); + + xy_to_pos(x1, y1, pos); + glVertex2d(pos[0], pos[1]); + + i++; + } + glEnd(); +} + +void draw_wave(phi, xy_in, scale, time) +/* draw the field */ +double *phi[NX], scale; +short int *xy_in[NX]; +int time; +{ + int i, j, iplus, iminus, jplus, jminus, ij[2], counter = 0; + static int first = 1; + double rgb[3], xy[2], x1, y1, x2, y2, dx, value, angle, dangle, intens, deltaintens, sum = 0.0; + double *nablax[NX], *nablay[NX]; + static double linex[N_FIELD_LINES*FIELD_LINE_FACTOR], liney[N_FIELD_LINES*FIELD_LINE_FACTOR], distance[N_FIELD_LINES*FIELD_LINE_FACTOR], integral[N_FIELD_LINES*FIELD_LINE_FACTOR + 1]; + + for (i=0; i 0) + compute_gradient(phi, nablax, nablay); + + /* compute the position of origins of field lines */ + if ((first)&&(DRAW_FIELD_LINES)) + { + first = 0; + + printf("computing linex\n"); + + x1 = sqrt(3.58); + y1 = 0.0; + linex[0] = x1; + liney[0] = y1; + dangle = DPI/((double)(N_FIELD_LINES*FIELD_LINE_FACTOR)); + + for (i = 1; i < N_FIELD_LINES*FIELD_LINE_FACTOR; i++) + { +// angle = PID + (double)i*dangle; + angle = (double)i*dangle; + x2 = sqrt(3.58)*cos(angle); + y2 = sqrt(1.18)*sin(angle); + linex[i] = x2; + liney[i] = y2; + distance[i-1] = module2(x2-x1,y2-y1); + x1 = x2; + y1 = y2; + } + distance[N_FIELD_LINES*FIELD_LINE_FACTOR - 1] = module2(x2-sqrt(3.58),y2); + } + + dx = (XMAX-XMIN)/((double)NX); + glBegin(GL_QUADS); + + for (i=0; i 0) integral[i] = integral[i-1] + intens; + else integral[i] = intens; + } + deltaintens = integral[N_FIELD_LINES*FIELD_LINE_FACTOR-1]/((double)N_FIELD_LINES); +// deltaintens = integral[N_FIELD_LINES*FIELD_LINE_FACTOR-1]/((double)N_FIELD_LINES + 1.0); +// deltaintens = integral[N_FIELD_LINES*FIELD_LINE_FACTOR-1]/((double)N_FIELD_LINES); + +// printf("delta = %.5lg\n", deltaintens); + + i = 0; +// draw_field_line(linex[0], liney[0], nablax, nablay, 0.00002, 100000); + draw_field_line(linex[0], liney[0], xy_in, nablax, nablay, 0.00002, 100000); + for (j = 1; j < N_FIELD_LINES+1; j++) + { + while ((integral[i] <= j*deltaintens)&&(i < N_FIELD_LINES*FIELD_LINE_FACTOR)) i++; +// draw_field_line(linex[i], liney[i], nablax, nablay, 0.00002, 100000); + draw_field_line(linex[i], liney[i], xy_in, nablax, nablay, 0.00002, 100000); + counter++; + } + printf("%i lines\n", counter); + } + + + for (i=0; i0)&&(i0)&&(j VMAX) phi[i][j] = VMAX; + if (newphi[i][j] < -VMAX) phi[i][j] = -VMAX; + } + } + } + } + + for (i=0; i= 0.0) sprintf(message, "c = %.5f + %.5f i", julia_x, julia_y); + else sprintf(message, "c = %.5f %.5f i", julia_x, julia_y); + xy_to_pos(XMIN + 0.1, YMAX - 0.2, pos); + write_text(pos[0], pos[1], message); +} + +void set_Julia_parameters(time, phi, xy_in) +int time; +double *phi[NX]; +short int *xy_in[NX]; +{ + double jangle, cosj, sinj, radius = 0.15; + + jangle = (double)time*DPI/(double)NSTEPS; +// jangle = (double)time*0.001; +// jangle = (double)time*0.0001; + + cosj = cos(jangle); + sinj = sin(jangle); + julia_x = -0.9 + radius*cosj; + julia_y = radius*sinj; + init_julia_set(phi, xy_in); + + printf("Julia set parameters : i = %i, angle = %.5lg, cx = %.5lg, cy = %.5lg \n", time, jangle, julia_x, julia_y); +} + +void set_Julia_parameters_cardioid(time, phi, xy_in) +int time; +double *phi[NX]; +short int *xy_in[NX]; +{ + double jangle, cosj, sinj, yshift; + + jangle = pow(1.05 + (double)time*0.00003, 0.333); + yshift = 0.02*sin((double)time*PID*0.002); +// jangle = pow(1.0 + (double)time*0.00003, 0.333); +// jangle = pow(0.05 + (double)time*0.00003, 0.333); +// jangle = pow(0.1 + (double)time*0.00001, 0.333); +// yshift = 0.04*sin((double)time*PID*0.002); + + cosj = cos(jangle); + sinj = sin(jangle); + julia_x = 0.5*(cosj*(1.0 - 0.5*cosj) + 0.5*sinj*sinj); + julia_y = 0.5*sinj*(1.0-cosj) + yshift; + /* need to decrease 0.05 for i > 2000 */ +// julia_x = 0.5*(cosj*(1.0 - 0.5*cosj) + 0.5*sinj*sinj); +// julia_y = 0.5*sinj*(1.0-cosj); + init_julia_set(phi, xy_in); + + printf("Julia set parameters : i = %i, angle = %.5lg, cx = %.5lg, cy = %.5lg \n", time, jangle, julia_x, julia_y); +} + +void animation() +{ + double time, scale, dx, var, jangle, cosj, sinj; + double *phi[NX]; + short int *xy_in[NX]; + int i, j, s; + + /* Since NX and NY are big, it seemed wiser to use some memory allocation here */ + for (i=0; i XMAX) + if (SCALING_FACTOR*x2 > XMAX) { glBegin(GL_LINE_STRIP); - glVertex2d(x1+XMIN-XMAX, y1); - glVertex2d(x2+XMIN-XMAX, y2); + glVertex2d(SCALING_FACTOR*(x1+XMIN-XMAX), SCALING_FACTOR*y1); + glVertex2d(SCALING_FACTOR*(x2+XMIN-XMAX), SCALING_FACTOR*y2); glEnd (); } - if (x2 < XMIN) + if (SCALING_FACTOR*x2 < XMIN) { glBegin(GL_LINE_STRIP); - glVertex2d(x1-XMIN+XMAX, y1); - glVertex2d(x2-XMIN+XMAX, y2); + glVertex2d(SCALING_FACTOR*(x1-XMIN+XMAX), SCALING_FACTOR*y1); + glVertex2d(SCALING_FACTOR*(x2-XMIN+XMAX), SCALING_FACTOR*y2); glEnd (); } - if (y2 > YMAX) + if (SCALING_FACTOR*y2 > YMAX) { glBegin(GL_LINE_STRIP); - glVertex2d(x1, y1+YMIN-YMAX); - glVertex2d(x2, y2+YMIN-YMAX); + glVertex2d(SCALING_FACTOR*x1, SCALING_FACTOR*(y1+YMIN-YMAX)); + glVertex2d(SCALING_FACTOR*x2, SCALING_FACTOR*(y2+YMIN-YMAX)); glEnd (); } - if (y2 < YMIN) + if (SCALING_FACTOR*y2 < YMIN) { glBegin(GL_LINE_STRIP); - glVertex2d(x1, y1+YMAX-YMIN); - glVertex2d(x2, y2+YMAX-YMIN); + glVertex2d(SCALING_FACTOR*x1, SCALING_FACTOR*(y1+YMAX-YMIN)); + glVertex2d(SCALING_FACTOR*x2, SCALING_FACTOR*(y2+YMAX-YMIN)); glEnd (); } } @@ -305,15 +318,15 @@ double *configs[NPARTMAX]; { glLineWidth(1.0); glBegin(GL_LINES); - glVertex2d(configs[i][4], configs[i][5]); - glVertex2d(configs[i][6], configs[i][7]); + glVertex2d(SCALING_FACTOR*configs[i][4], SCALING_FACTOR*configs[i][5]); + glVertex2d(SCALING_FACTOR*configs[i][6], SCALING_FACTOR*configs[i][7]); glEnd (); glLineWidth(3.0); } if (configs[i][2] > configs[i][3] - DPHI) configs[i][2] -= configs[i][3]; } - draw_billiard(); + if (DRAW_BILLIARD) draw_billiard(); } @@ -355,9 +368,9 @@ double *configs[NPARTMAX]; void animation() { - double time, dt, alpha; + double time, dt, alpha, r; double *configs[NPARTMAX]; - int i, j, resamp = 1, s; + int i, j, resamp = 1, s, i1, i2; int *color, *newcolor, *active; /* Since NPARTMAX can be big, it seemed wiser to use some memory allocation here */ @@ -368,19 +381,21 @@ void animation() configs[i] = (double *)malloc(8*sizeof(double)); /* initialize system by putting particles in a given point with a range of velocities */ - alpha = 3.0*PI/7.0; - init_sym_drop_config(-0.99, 0.0, -alpha, alpha, configs); + r = cos(PI/(double)NPOLY)/cos(DPI/(double)NPOLY); + +// init_drop_config(0.0, 0.0, -0.2, 0.2, configs); +// init_drop_config(0.5, 0.5, -1.0, 1.0, configs); +// init_sym_drop_config(-1.0, 0.5, -PID, PID, configs); // init_drop_config(-0.999, 0.0, -alpha, alpha, configs); -// init_drop_config(0.0, 0.5, 0.0, DPI, configs); // other possible initial conditions : // init_line_config(-0.6, 0.2, -0.6, 0.7, 0.0, configs); // init_line_config(-0.7, -0.45, -0.7, 0.45, 0.0, configs); -// init_line_config(0.0, 0.1, 0.0, 0.7, 0.0, configs); + init_line_config(0.0, -0.3, 0.0, 0.3, 0.0, configs); blank(); glColor3f(0.0, 0.0, 0.0); - draw_billiard(); + if (DRAW_BILLIARD) draw_billiard(); glutSwapBuffers(); @@ -391,6 +406,24 @@ void animation() newcolor[i] = 0; active[i] = 1; } + + if (FLOWER_COLOR) /* adapt color scheme to flower configuration (beta implementation) */ + { +// i1 = (int)((double)NPART*0.2538); /* the 0.27 is just a trial-and-error guess, to be improved */ +// i1 = (int)((double)NPART*0.1971); /* the 0.27 is just a trial-and-error guess, to be improved */ + i1 = (int)((double)NPART*0.3015); /* the 0.27 is just a trial-and-error guess, to be improved */ + i2 = NPART-i1; + for (i=i1; i0)&&(i0)&&(j VMAX) phi[i][j] = VMAX; - if (phi[i][j] < -VMAX) phi[i][j] = -VMAX; - if (psi[i][j] > VMAX) psi[i][j] = VMAX; - if (psi[i][j] < -VMAX) psi[i][j] = -VMAX; + if (newphi[i][j] > VMAX) newphi[i][j] = VMAX; + if (newphi[i][j] < -VMAX) newphi[i][j] = -VMAX; + if (newpsi[i][j] > VMAX) newpsi[i][j] = VMAX; + if (newpsi[i][j] < -VMAX) newpsi[i][j] = -VMAX; } } } } + + + for (i=0; i 0.0) x2 = cos(omega*0.5) + sqrt(LAMBDA*LAMBDA - sin(omega*0.5)*sin(omega*0.5)); + else x2 = cos(omega*0.5) - sqrt(LAMBDA*LAMBDA - sin(omega*0.5)*sin(omega*0.5)); + + if (PAINT_INT) + { + if (BLACK) glColor3f(1.0, 1.0, 1.0); + else glColor3f(0.0, 0.0, 0.0); + + glBegin(GL_TRIANGLE_FAN); + glVertex2d(0.0, 0.0); + for (i=0; i<=NPOLY; i++) + { + for (j=0; j 0.0)&&(intb)) /* check if condition is ok */ + ca = cos(rangle); + sa = sin(rangle); + + x = pos[0]*ca + pos[1]*sa; + y = -pos[0]*sa + pos[1]*ca; + + a = (x-x2)*cos(theta) + y*sin(theta); + b = (x-x2)*(x-x2) + y*y - LAMBDA*LAMBDA; + + if (a*a - b > margin) { - ca = cos(rangle); - sa = sin(rangle); - -// printf("theta = %.5lg\n", theta); -// printf("rangle = %.5lg x0 = %.5lg y0 = %.5lg \n", rangle, pos[0], pos[1]); - - x = pos[0]*ca + pos[1]*sa; - y = -pos[0]*sa + pos[1]*ca; - -// printf("x = %.5lg\t y = %.5lg\n", x, y); - - a = (x-x2)*cos(theta) + y*sin(theta); - b = (x-x2)*(x-x2) + y*y - LAMBDA*LAMBDA; - -// printf("a = %.5lg\t b = %.5lg\n", a, b); - - if (a*a - b > margin) + if (LAMBDA > 0.0) t = -a - sqrt(a*a - b); + else t = -a + sqrt(a*a - b); + + xi = x + t*cos(theta); + yi = y + t*sin(theta); + + if ((t > margin)&&(vabs(yi) <= sin(omega2))) { -// t = vabs(a) - sqrt(a*a - b); - if (LAMBDA > 0.0) t = -a - sqrt(a*a - b); - else t = -a + sqrt(a*a - b); - - xi = x + t*cos(theta); - yi = y + t*sin(theta); - -// printf("t = %.5lg\t xi = %.5lg\t yi = %.5lg\n", t, xi, yi); - - if ((t > margin)&&(vabs(yi) <= sin(omega2))) - { - cval[nt] = k; - tval[nt] = t; + cval[nt] = k; + tval[nt] = t; - /* rotate back */ - x1[nt] = xi*ca - yi*sa; - y1[nt] = xi*sa + yi*ca; + /* rotate back */ + x1[nt] = xi*ca - yi*sa; + y1[nt] = xi*sa + yi*ca; -// intb = 0; -// c = k; - tempconf[nt][0] = ((double)k + 0.5)*beta + asin(yi/LAMBDA); - tempconf[nt][1] = PID - asin(yi/LAMBDA) - theta; -// tempconf[nt][0] = ((double)k + 0.5)*beta + asin(yi/vabs(LAMBDA)); -// tempconf[nt][1] = PID - asin(yi/vabs(LAMBDA)) - theta; - nt++; - } + tempconf[nt][0] = ((double)k + 0.5)*beta + asin(yi/LAMBDA); + tempconf[nt][1] = PID - asin(yi/LAMBDA) - theta; + nt++; } } } -// printf("nt = %i\n", nt); /* find earliest intersection */ tmin = tval[0]; @@ -1783,6 +1952,390 @@ int color[NPARTMAX]; return(c); } + +/****************************************************************************************/ +/* Bunimovich flower billiard */ +/****************************************************************************************/ + + int pos_flower(conf, pos, alpha) + /* determine position on boundary of polygon */ + /* conf[0] is arclength on boundary, it belongs to [0,2*NPOLY*phimax) */ + double conf[2], pos[2], *alpha; + + { + double s, theta, omega, co, so, axis1, axis2, phimax, s1, x, y, angle; + int c; + + s = conf[0]; + theta = conf[1]; + + compute_flower_parameters(&omega, &co, &so, &axis1, &axis2, &phimax); + + c = (int)(s/(2.0*phimax)); /* side of shape */ + + s1 = s - (((double)c)*2.0 + 1.0)*phimax; + + x = co + axis1*cos(s1); + y = axis2*sin(s1); + + angle = ((double)c)*omega + PID*APOLY; +// angle = 2.0*((double)c)*omega + PID*APOLY; + + pos[0] = x*cos(angle) - y*sin(angle); + pos[1] = x*sin(angle) + y*cos(angle); + + *alpha = argument(-axis1*sin(s1), axis2*cos(s1)) + theta + angle; + +// printf("alpha = %.5lg\t", *alpha); + + return(c); + } + + int vflower_xy(config, alpha, pos) + /* determine initial configuration for start at point pos = (x,y) */ + double config[8], alpha, pos[2]; + + { + double s, theta, omega, omega2, s1, rangle, x, y, x1, y1, xi, yi, t; + double ca, sa, aa, bb, cc, margin = 1.0e-14, tmin; + double co, so, co2, so2, ct, st, phimax, phi, axis1, axis2; + int k, c, intb=1, intc, i, nt = 0, ntmin, sign; + + compute_flower_parameters(&omega, &co, &so, &axis1, &axis2, &phimax); + + for (k=0; k margin) + if (bb*bb - aa*cc >= 0.0) + { + t = (-bb + sqrt(bb*bb - aa*cc))/aa; + + xi = x + t*cos(theta); + yi = y + t*sin(theta); + + if (yi >= 0.0) phi = argument((xi - co)/axis1, yi/axis2); + else phi = -argument((xi - co)/axis1, -yi/axis2); + + if ((t > margin)&&((vabs(phi) <= phimax)||(vabs(phi-DPI) <= phimax))) + { + intb = 0; + c = k; + + /* rotate back */ + x1 = xi*ca - yi*sa; + y1 = xi*sa + yi*ca; + + config[0] = (double)(2*k + 1)*phimax + phi; + config[1] = argument(-axis1*sin(phi), axis2*cos(phi)) - theta; + } + } + } + +// if (nt == 0) printf("nt = %i\t ntmin = %i \tcmin = %i\n", nt, ntmin, c); + + if (config[1] < 0.0) config[1] += DPI; + + config[2] = 0.0; /* running time */ + config[3] = module2(x1-pos[0], y1-pos[1]); /* distance to collision */ + config[4] = pos[0]; /* start position */ + config[5] = pos[1]; + config[6] = x1; /* position of collision */ + config[7] = y1; + + return(c); + } + + int old_vflower_xy(config, alpha, pos) + /* determine initial configuration for start at point pos = (x,y) */ + double config[8], alpha, pos[2]; + + { + double s, theta, omega, omega2, s1, rangle, x, y, x1[2*NPOLY], y1[2*NPOLY], xi, yi, t; + double ca, sa, aa, bb, cc, margin = 1.0e-14, tmin, tval[2*NPOLY], tempconf[2*NPOLY][2]; + double co, so, co2, so2, ct, st, phimax, phi, axis1, axis2; + int k, c, intb=1, intc, i, nt = 0, cval[2*NPOLY], ntmin, sign; + + compute_flower_parameters(&omega, &co, &so, &axis1, &axis2, &phimax); + + for (k=0; k margin) + if (bb*bb - aa*cc >= 0.0) + { + t = (-bb + sqrt(bb*bb - aa*cc))/aa; + + xi = x + t*cos(theta); + yi = y + t*sin(theta); + + if (yi >= 0.0) phi = argument((xi - co)/axis1, yi/axis2); + else phi = -argument((xi - co)/axis1, -yi/axis2); + +// phi = argument((xi - co)/axis1, yi/axis2); +// if (phi > PI) phi += -DPI; + + if ((t > margin)&&((vabs(phi) <= phimax)||(vabs(phi-DPI) <= phimax))) +// if (((vabs(phi) <= phimax)||(vabs(phi-DPI) <= phimax))) +// if ((t > margin)) + { + cval[nt] = k; +// cval[nt] = 2*k; + tval[nt] = t; + + /* rotate back */ + x1[nt] = xi*ca - yi*sa; + y1[nt] = xi*sa + yi*ca; + + tempconf[nt][0] = (double)(2*k + 1)*phimax + phi; + tempconf[nt][1] = argument(-axis1*sin(phi), axis2*cos(phi)) - theta; + nt++; + } + } + } + + /* find earliest intersection */ + tmin = tval[0]; + ntmin = 0; + for (i=1; i margin) + { + if (k%2==0) t = -a - sqrt(a*a - b); + else t = -a + sqrt(a*a - b); + + xi = x + t*cos(theta); + yi = y + t*sin(theta); + + if ((t > margin)&&(vabs(yi) <= sin(omega2))) + { + cval[nt] = k; + tval[nt] = t; + + /* rotate back */ + x1[nt] = xi*ca - yi*sa; + y1[nt] = xi*sa + yi*ca; + + if (k%2==0) arcsine = asin(yi/LAMBDA); + else arcsine = -asin(yi/LAMBDA); + + tempconf[nt][0] = ((double)k + 0.5)*beta + arcsine; + tempconf[nt][1] = PID - arcsine - theta; + nt++; + } + } + } + + /* find earliest intersection */ + tmin = tval[0]; + ntmin = 0; + for (i=1; i l2)&&(r2 < 1.0)) return(1); + r1 = x*x + y*y; + r2 = (x-MU)*(x-MU) + y*y; + if ((r2 > l2)&&(r1 < 1.0)) return(1); else return(0); break; } @@ -2056,22 +2644,42 @@ int color[NPARTMAX]; y1 = -x*sin(angle) + y*cos(angle); if (LAMBDA > 0.0) condition = condition*((x1-x2)*(x1-x2) + y1*y1 > LAMBDA*LAMBDA); else condition = condition*((x1-x2)*(x1-x2) + y1*y1 < LAMBDA*LAMBDA); - -// if (!condition) -// { -// printf("x = %.5lg \t y = %.5lg \t x1 = %.5lg \t y1 = %.5lg \t angle = %.5lg \n", x, y, x1, y1, angle); -// printf("k = %i \t condition = %i\n", k, condition); -// sleep(1); -// } } return(condition); break; } /* D_REULEAUX : distance to all centers of arcs should be larger than LAMBDA */ + case D_FLOWER: + { + /* TO DO */ + return(1); + break; + } + case D_ALT_REU: + { + condition = 1; + omega2 = PI/((double)NPOLY); + co = cos(omega2); + so = sin(omega2); + x2plus = co + sqrt(LAMBDA*LAMBDA - so*so); + x2minus = co - sqrt(LAMBDA*LAMBDA - so*so); + + for (k=0; k LAMBDA*LAMBDA); + else condition = condition*((x1-x2minus)*(x1-x2minus) + y1*y1 < LAMBDA*LAMBDA); + } + return(condition); + break; + } default: { printf("Function ij_in_billiard not defined for this billiard \n"); - return(0); + return(1); } } } diff --git a/sub_wave.c b/sub_wave.c index 58c921d..187b31b 100644 --- a/sub_wave.c +++ b/sub_wave.c @@ -198,6 +198,7 @@ void write_text( double x, double y, char *st) + /*********************/ /* some basic math */ /*********************/ @@ -296,6 +297,22 @@ double xy[2]; xy[1] = YMIN + ((double)j)*(YMAX-YMIN)/((double)NY); } +void draw_rectangle(x1, y1, x2, y2) +double x1, y1, x2, y2; +{ + double pos[2]; + + glBegin(GL_LINE_LOOP); + xy_to_pos(x1, y1, pos); + glVertex2d(pos[0], pos[1]); + xy_to_pos(x2, y1, pos); + glVertex2d(pos[0], pos[1]); + xy_to_pos(x2, y2, pos); + glVertex2d(pos[0], pos[1]); + xy_to_pos(x1, y2, pos); + glVertex2d(pos[0], pos[1]); + glEnd(); +} @@ -303,7 +320,7 @@ int xy_in_billiard(x, y) /* returns 1 if (x,y) represents a point in the billiard */ double x, y; { - double l2, r2, omega, c, angle, z; + double l2, r2, r2mu, omega, c, angle, z, x1, y1, u, v, u1, v1; int i, k, k1, k2, condition; switch (B_DOMAIN) { @@ -399,6 +416,124 @@ double x, y; { return(((x-1.0)*(x-1.0) + y*y < LAMBDA*LAMBDA)||((x+1.0)*(x+1.0) + y*y < LAMBDA*LAMBDA)||((vabs(x) < 1.0)&&(vabs(y) < MU))); } + case D_MENGER: + { + x1 = 0.5*(x+1.0); + y1 = 0.5*(y+1.0); + for (k=0; k l2)&&(r2 < 1.0)) return(1); + else if (r2mu <= l2) return(2); + else return (0); + } + case D_MENGER_HEATED: + { + if ((vabs(x) >= 1.0)||(vabs(y) >= 1.0)) return(0); + else + { + x1 = 0.5*(x+1.0); + y1 = 0.5*(y+1.0); + for (k=0; k 1.2) return(2); + else return(1); + } + case D_MANDELBROT_CIRCLE: + { + u = 0.0; + v = 0.0; + i = 0; + while ((i 1.2) return(2); +// else if ((vabs(x) > XMAX - 0.01)||(vabs(y) > YMAX - 0.01)) return(2); + else return(1); + } default: { printf("Function ij_in_billiard not defined for this billiard \n"); @@ -423,8 +558,8 @@ int i, j; void draw_billiard() /* draws the billiard boundary */ { - double x0, x, y, phi, r = 0.01, pos[2], pos1[2], alpha, dphi, omega, z; - int i, j, k1, k2; + double x0, x, y, phi, r = 0.01, pos[2], pos1[2], alpha, dphi, omega, z, l; + int i, j, k1, k2, mr2; if (BLACK) glColor3f(1.0, 1.0, 1.0); else glColor3f(0.0, 0.0, 0.0); @@ -710,7 +845,195 @@ void draw_billiard() /* draws the billiard boundary */ glEnd (); break; } - default: + case (D_MENGER): + { + glLineWidth(3); +// draw_rectangle(XMIN, -1.0, XMAX, 1.0); + + /* level 1 */ + if (MDEPTH > 0) + { + glLineWidth(2); + x = 1.0/((double)MRATIO); + draw_rectangle(x, x, -x, -x); + } + + /* level 2 */ + if (MDEPTH > 1) + { + glLineWidth(1); + mr2 = MRATIO*MRATIO; + l = 2.0/((double)mr2); + + for (i=0; i 2) + { + glLineWidth(1); + l = 2.0/((double)(mr2*MRATIO)); + + for (i=0; i 0) + { + glLineWidth(2); + x = 1.0/((double)MRATIO); + draw_rectangle(x, x, -x, -x); + } + + /* level 2 */ + if (MDEPTH > 1) + { + glLineWidth(1); + mr2 = MRATIO*MRATIO; + l = 2.0/((double)mr2); + + for (i=0; i 2) + { + glLineWidth(1); + l = 2.0/((double)(mr2*MRATIO)); + + for (i=0; i 0) + { + glLineWidth(2); + x = 1.0/((double)MRATIO); + draw_rectangle(x, x, -x, -x); + } + + /* level 2 */ + if (MDEPTH > 1) + { + glLineWidth(1); + mr2 = MRATIO*MRATIO; + l = 2.0/((double)mr2); + + for (i=0; i 2) + { + glLineWidth(1); + l = 2.0/((double)(mr2*MRATIO)); + + for (i=0; i= NX) imax = NX-1; + jmin = ij1[1] - d; if (jmin < 0) jmin = 0; + jmax = ij2[1] + d; if (jmax >= NY) jmax = NY-1; + + for (i = imin; i < imax; i++) + for (j = jmin; j < jmax; j++) + { + ij_to_xy(i, j, xy); + dist2 = (xy[0]-x1)*(xy[0]-x1); /* to be improved */ +// dist2 = (xy[0]-x)*(xy[0]-x) + (xy[1]-y)*(xy[1]-y); +// if (dist2 < 0.01) + if (dist2 < 0.001) + phi[i][j] = amplitude*exp(-dist2/0.001)*cos(-sqrt(dist2)/0.01)*cos(t*OMEGA); +// phi[i][j] += 0.2*exp(-dist2/0.001)*cos(-sqrt(dist2)/0.01)*cos(t*OMEGA); + } +} + @@ -215,7 +295,92 @@ int time; glEnd (); } -void evolve_wave(phi, psi, xy_in) +void evolve_wave_half(phi_in, psi_in, phi_out, psi_out, xy_in) +/* time step of field evolution */ +/* phi is value of field at time t, psi at time t-1 */ + double *phi_in[NX], *psi_in[NX], *phi_out[NX], *psi_out[NX]; short int *xy_in[NX]; +{ + int i, j, iplus, iminus, jplus, jminus; + double delta, x, y, c, cc; + + c = COURANT; + cc = courant2; + + #pragma omp parallel for private(i,j,iplus,iminus,jplus,jminus,delta,x,y) + for (i=0; i0)&&(i0)&&(j VMAX) phi_out[i][j] = VMAX; + if (phi_out[i][j] < -VMAX) phi_out[i][j] = -VMAX; + if (psi_out[i][j] > VMAX) psi_out[i][j] = VMAX; + if (psi_out[i][j] < -VMAX) psi_out[i][j] = -VMAX; + } + } + } + } +// printf("phi(0,0) = %.3lg, psi(0,0) = %.3lg\n", phi[NX/2][NY/2], psi[NX/2][NY/2]); +} + + +void evolve_wave(phi, psi, phi_tmp, psi_tmp, xy_in) +/* time step of field evolution */ +/* phi is value of field at time t, psi at time t-1 */ + double *phi[NX], *psi[NX], *phi_tmp[NX], *psi_tmp[NX]; short int *xy_in[NX]; +{ + evolve_wave_half(phi, psi, phi_tmp, psi_tmp, xy_in); + evolve_wave_half(phi_tmp, psi_tmp, phi, psi, xy_in); +} + +void old_evolve_wave(phi, psi, xy_in) /* time step of field evolution */ /* phi is value of field at time t, psi at time t-1 */ double *phi[NX], *psi[NX]; short int *xy_in[NX]; @@ -286,7 +451,7 @@ double compute_variance(phi, psi, xy_in) void animation() { double time, scale; - double *phi[NX], *psi[NX]; + double *phi[NX], *psi[NX], *phi_tmp[NX], *psi_tmp[NX]; short int *xy_in[NX]; int i, j, s; @@ -295,12 +460,15 @@ void animation() { phi[i] = (double *)malloc(NY*sizeof(double)); psi[i] = (double *)malloc(NY*sizeof(double)); + phi_tmp[i] = (double *)malloc(NY*sizeof(double)); + psi_tmp[i] = (double *)malloc(NY*sizeof(double)); xy_in[i] = (short int *)malloc(NY*sizeof(short int)); } courant2 = COURANT*COURANT; /* initialize wave with a drop at one point, zero elsewhere */ +// init_wave_flat(phi, psi, xy_in); init_wave(0.0, 0.0, phi, psi, xy_in); /* add a drop at another point */ @@ -329,12 +497,19 @@ void animation() scale = sqrt(1.0 + compute_variance(phi,psi, xy_in)); // printf("Scaling factor: %5lg\n", scale); } - else scale = 1.0; +// /* TO BE ADAPTED */ +// scale = 1.0; draw_wave(phi, psi, xy_in, scale, i); - for (j=0; j