#include "Swarming.H" #define rhoGrid 300 // Number of mesh grids while computing density struct linearad_common { double statelft,statergt,alpha,beta,ca,la,cr,lr,lc; }; extern linearad_common F77NAME(linearad); //model parameters struct machine_common { double roundoff,small,huge,undefind; //machine dependent constants }; extern machine_common F77NAME(machine); int ncells; // number of particles int gcells; // number of "ghost particles" int nsteps; // total number of time steps (not used anymore) int stpstp; // output results every 'stpstp' time steps double tmax; // total simulation time (not used anymore) double tstp; // time step length int nonlin_f; // whether to use non-linear propelsion (not used anymore) int fm; // first mesh grid label (not used here) int lm; // last mesh grid label (not used here) int ifirst; // first partical label int ilast; // last partical label int ori_last; // original last partical label (not including ghosts) double *xold; // old position and velocity double *xnew; // new position and velocity double *xm; // position array used by RK4 method double *vm; // velocity array used by RK 4 method double *km, *km1, *km2, *km3, *Gforce; // used by numerical methods double *x, *y, *u, *v, *temp; // defining x, y, u, v arrays double rho[6*rhoGrid]; // array to store radial density...etc. double max_dist; // upper bound for the 2nd figure double radialdensity[rhoGrid]; // store radial density for the figure double polar,momen; // polarization and angular momentum // The following are variables used by the OpenGL library. int swarming_id, plot_id; // window id's int halt_n=0; // halt the simulation? int add_p=0; // adding particles? int finish_add_p=1; // finish adding? double add_x, add_y, add_u, add_v; // the pos/vel of the added long step=0; // simulationg steps double t=0.; // simulation time int reset_time=0; int main(int argc,char* argv[]) { void simulation_default(void); void simulation_init(void); void main_display(void); void plot_display(void); void graph_init(void); void idle(void); void keyCB(unsigned char, int, int); void mouseCB(int, int, int, int); void motionCB(int, int); void entryCB(int); void sw_menu(int); /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c 1. set the default constants and parameter values c 2. read parameters from the input file c 3. initiate the variable arrays with initial conditions +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ simulation_default(); readinput(argc, argv, &ncells, &gcells, &nsteps, &stpstp, &tmax, &tstp, &nonlin_f); simulation_init(); /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c initiate the graphics +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(-1,-1); glutInitWindowSize(size_W,size_H); swarming_id = glutCreateWindow("Swarming"); /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c Create a menu ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ glutCreateMenu(sw_menu); glutAddMenuEntry("Continue", 1); glutAddMenuEntry("Pause", 2); glutAddMenuEntry("Pause and save data as sw.dat", 3); glutAddMenuEntry("Increase velocity by 10%%", 4); glutAddMenuEntry("Quit", 5); glutAttachMenu(GLUT_RIGHT_BUTTON); /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c initiate graph and define call back subroutines +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ graph_init(); glutDisplayFunc(main_display); glutIdleFunc(idle); glutKeyboardFunc(keyCB); glutMouseFunc(mouseCB); glutMotionFunc(motionCB); glutEntryFunc(entryCB); /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c Create a second window ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); glutInitWindowSize(300,300); plot_id = glutCreateWindow("Momentum and Polarization"); /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ initiate the second window and define its call back subroutines ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ graph_init(); glutDisplayFunc(plot_display); glutMainLoop(); return(0); } /******************************************************************** * This subroutine sets default values to the machine-dependent * * constants and the model parameters. * ********************************************************************/ void simulation_default(void) { // set machine-dependent constants for Fortran F77NAME(machine).roundoff=DBL_EPSILON; F77NAME(machine).small=DBL_MIN; F77NAME(machine).huge=DBL_MAX; F77NAME(machine).undefind=HUGE_VAL; // set default values for problem parameters F77NAME(linearad).statelft=500.; F77NAME(linearad).statergt=-500.; F77NAME(linearad).alpha=10.; F77NAME(linearad).beta=1.; F77NAME(linearad).ca=0.4; F77NAME(linearad).la=40.; F77NAME(linearad).cr=1.; F77NAME(linearad).lr=20.; F77NAME(linearad).lc=5.; ncells=10; gcells=10; nsteps=10; stpstp=10; tmax=1.; tstp=0.01; nonlin_f=0; } /***************************************************************** * This subroutine creates arrays to store particle positions * * and velocities as well as arrays needed by the RK4 method. * * It then sets the initial conditions for the simulation. * *****************************************************************/ void simulation_init(void) { // array bounds for Fortran calls fm=0; lm=ncells + gcells -1; ifirst=0; ilast=ncells-1; ori_last=ilast; ncells = ncells + gcells; // since ncells is determined dynamically, // must use dynamic memory allocation xold=(double*)malloc(4*ncells*sizeof(double)); xnew=(double*)malloc(4*ncells*sizeof(double)); xm=(double*)malloc(2*ncells*sizeof(double)); vm=(double*)malloc(2*ncells*sizeof(double)); km=(double*)malloc(4*ncells*sizeof(double)); km1=(double*)malloc(4*ncells*sizeof(double)); km2=(double*)malloc(4*ncells*sizeof(double)); km3=(double*)malloc(4*ncells*sizeof(double)); Gforce=(double*)malloc(2*ncells*sizeof(double)); x=xold; y=xold+ncells; u=xold+2*ncells; v=xold+3*ncells; // The variables are initiated with a huge value first // and then re-initiated to the desired initial conditions { for (int i=0;i<4*ncells;i++) { xold[i]=HUGE_VAL; xnew[i]=HUGE_VAL; km[i]=HUGE_VAL; } for (int i=0;i<2*ncells;i++) { xm[i]=HUGE_VAL; vm[i]=HUGE_VAL; } reinitiate(ncells, ifirst,ilast,xold); } /*+++++++++++++++++++++++++++++++++++++++++++++++ c radialdensity[] array is initiated with 1.0. c max_dist is initiated as 1.0 c +++++++++++++++++++++++++++++++++++++++++++++++++*/ { max_dist = 1.0; for (int i=0; i0.) { glutSetWindow(swarming_id); glutPostRedisplay(); glutSetWindow(plot_id); glutPostRedisplay(); } } else if(add_p == 1) AddParticle(); } /****************************************************************** * The keyboard event subroutine, defining the functions for * * keyboard input events. * ******************************************************************/ void keyCB(unsigned char key, int mx, int my) { if(key == 'r' || key == 'R') halt_n=0; else if(key == 's' || key == 'S') halt_n=1; else if(key == 'q' || key == 'Q') { delete [] xold; delete [] xnew; delete [] xm; delete [] vm; delete [] km; exit(0); } } /********************************************************************** * The mouse event subroutine, defining the functions for mouse * * clicking. * **********************************************************************/ void mouseCB(int button, int state, int mx, int my) { if(state == GLUT_DOWN && button == GLUT_LEFT_BUTTON && halt_n ==1) { add_p = 1; finish_add_p = 0; add_x = (double)mx/(double)size_W; add_y = 1.0-(double)my/(double)size_H; add_u = 0.; add_v = 0.; printf("add_x=%lf, add_y=%lf\n", add_x, add_y); } if(state == GLUT_UP && button == GLUT_LEFT_BUTTON && add_p ==1) { finish_add_p = 1; } } /*********************************************************************** * The mouse motion subroutine, defining the function for mouse * * motion. * ***********************************************************************/ void motionCB(int mx, int my) { if(halt_n == 1) { add_u = (double)mx/(double)size_W; add_v = 1.0-(double)my/(double)size_H; } } /*********************************************************************** * The mouse entry subroutine, defineing the function for the * * situation when mouse leaves the window. * ***********************************************************************/ void entryCB(int mstate) { if(mstate == GLUT_LEFT) add_p = 0; } /*********************************************************************** * The menu call back subroutine, defining the function for each * * menu items. * ***********************************************************************/ void sw_menu(int menu_value) { if(menu_value == 1) halt_n = 0; if(menu_value == 2) halt_n = 1; if(menu_value == 3) { char filename[10]; sprintf(filename, "sw.dat"); writeout(4, ncells, xold, filename); halt_n = 1; } if(menu_value == 4) { for(int ic=ifirst; ic<=ilast; ic++) { xold[2*ncells+ic] *= 1.1; xold[3*ncells+ic] *= 1.1; xnew[2*ncells+ic] *= 1.1; xnew[3*ncells+ic] *= 1.1; } reset_time = 1; } if(menu_value == 5) exit(0); } /******************************************************************* * Running the swarming simulation. * *******************************************************************/ void running(void) { // static double t=0.; static double print_t=30.; static double dt = tstp; // static long step; /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c some time step resetting situations: c 1. if step=100000, reset to 0 (so that it won't exceed the limit c 2. if adding new particles is finished, reset step to 0, so that c the simulation will do the first 4 steps using the RK4 method. c 3. if reset_time=1, reset time and time step. c +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ if(step==100000) step=0; if(finish_add_p == 2) { step=0; finish_add_p = 1; } if(reset_time==1) { step=0; t=0.; reset_time=0; } /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c Simulation: first 5 steps are using the 4th order Runge-Kutta method; c then, the 4-step Adam-Bashforth method are used. c +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ if(step<5) F77NAME(method)(t,dt,fm,lm,ifirst,ilast, xold, xnew, xm, vm, km); else F77NAME(fourstep)(t,dt,fm,lm,ifirst,ilast,xold,xnew,km,km1,km2,km3, Gforce); t+=dt; step++; { temp = xold; xold = xnew; xnew = temp; temp = km3; km3 = km2; km2 = km1; km1 = km; km = temp; x = xold; y = xold+ncells; u = xold+2*ncells; v = xold+3*ncells; } /*+++++++++++++++++++++++++++++++++++++++++++++++++ c Calculate group properties every 100 time steps. c +++++++++++++++++++++++++++++++++++++++++++++++++++*/ if((step%100)==0) { static double dr, max_dist; // dr: mesh size of r, max_dist: max r static int avg_count; // counting for time averaging int cw,ccw; // counting the # of CW and CCW particles static double acc_density[rhoGrid]; //accumulated density static double acc_momr[rhoGrid]; //accumulated radial momentum static double acc_momt[rhoGrid]; //accumulated tangential momentum static double acc_sigk[rhoGrid]; //not used here (thermal fluctuation) static double acc_sigv[rhoGrid]; //not used here (interaction) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c Call "group" subroutine to compute group properties from xnew: c polar: polarity, c momen: angular momentum, c rho: density, c dr: mesh size of r, calculated from maximum r / rhoGrid, c cw,ccw: # of particles in CW and CCW states, c Gforce: interaction force. c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ F77NAME(group)(fm,lm,ifirst,ilast,xnew,polar,momen,rhoGrid,rho,dr, cw,ccw,Gforce); /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c Start to calculate the accumulated quantities if c (1) angular momentum is close to 1 or -1 (getting into rotation) c or c (2) time > 200 c +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ if((momen<0.995 && momen>-0.995)&&(t<200.)) { max_dist = dr*rhoGrid; //maximum r dr = 0.; // reset dr so that it will be recalculated in "group" for(int ie=0; iexhi) xhi=xi; else if(xi>xhihi) xhihi=xi; } // xlo=xlolo; // use the second limit as the figure boundary // xhi=xhihi; double ylo=y[0]-0.5; double yhi=y[0]+0.5; double ylolo=ylo; double yhihi=yhi; for (int ic=ifirst;ic<=ilast;ic++) { double yi=y[ic]; if (yiyhi) yhi=yi; else if(yi>yhihi) yhihi=yi; } // ylo=ylolo; // use the second limit as the figure boundary // yhi=yhihi; /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c Calculate the horizontal and vertical lengths as well as the origin. c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ double centerx, centery, hlength, vlength; hlength = xhi-xlo; vlength = yhi-ylo; centerx = (xhi+xlo)*0.5; centery = (yhi+ylo)*0.5; /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c In order to keep the figure as a square, we replace the shorter c length with the longer one and recalculate the upper and lower bound c of the corresponding axis. c We also extend the boundary by 0.5 unit so that we will have a c better view of the particles exactly on the edges. c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ if(hlength > vlength) { yhi = centery + 0.5*hlength +0.5; ylo = centery - 0.5*hlength -0.5; xhi = xhi + 0.5; xlo = xlo - 0.5; hlength = hlength +1.0; vlength = hlength; } else { xhi = centerx + 0.5*vlength +0.5; xlo = centerx - 0.5*vlength -0.5; yhi = yhi + 0.5; ylo = ylo - 0.5; vlength = vlength +1.0; hlength = vlength; } /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c Calculate the relative location of the origin in the figure. c (because the figure is setup as a (0,1)x(0,1) box.) c +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ centerx = (0.0-xlo)/hlength; centery = (0.0-ylo)/vlength; /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c The OpenGL drawing routine begins. c +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ glClear(GL_COLOR_BUFFER_BIT); /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c Draw the axes in black. c +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ glColor3f(0.0, 0.0, 0.0); gtDrawAxis(xlo, xhi, ylo, yhi); /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c Draw the original particles in blue. c (ic = ifirst to ori_last) c +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ glBegin(GL_LINES); int ic=ifirst; double width=0.01; double ptx = x[ic]/hlength + centerx; double pty = y[ic]/vlength + centery; double ptu = u[ic]/hlength; double ptv = v[ic]/vlength; double vlen = sqrt(ptu*ptu+ptv*ptv); glColor3f(0.0, 0.0, 1.0); glVertex2f(ptx-width, pty); glVertex2f(ptx+width, pty); glVertex2f(ptx, pty-width); glVertex2f(ptx, pty+width); // glColor3f(1.0, 0.0, 0.0); glVertex2f(ptx, pty); glVertex2f(ptx+0.05*ptu/vlen, pty+0.05*ptv/vlen); for (ic=ifirst+1;ic<=ori_last;ic++) { double ptx = x[ic]/hlength + centerx; double pty = y[ic]/vlength + centery; double ptu = u[ic]/hlength; double ptv = v[ic]/vlength; double vlen = sqrt(ptu*ptu+ptv*ptv); // glColor3f(0.0, 0.0, 1.0); glVertex2f(ptx-width, pty); glVertex2f(ptx+width, pty); glVertex2f(ptx, pty-width); glVertex2f(ptx, pty+width); // glColor3f(1.0, 0.0, 0.0); glVertex2f(ptx, pty); glVertex2f(ptx+0.05*ptu/vlen, pty+0.05*ptv/vlen); } /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c Draw the added particles in red. c (ic = ori_last+1 to ilast) c +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ for (ic=ori_last+1;ic<=ilast;ic++) { double ptx = x[ic]/hlength + centerx; double pty = y[ic]/vlength + centery; double ptu = u[ic]/hlength; double ptv = v[ic]/vlength; double vlen = sqrt(ptu*ptu+ptv*ptv); glColor3f(1.0, 0.0, 0.0); glVertex2f(ptx-width, pty); glVertex2f(ptx+width, pty); glVertex2f(ptx, pty-width); glVertex2f(ptx, pty+width); // glColor3f(0.0, 1.0, 0.0); glVertex2f(ptx, pty); glVertex2f(ptx+0.05*ptu/vlen, pty+0.05*ptv/vlen); } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ c Draw the newly added particles using information from mouse c clicking events. c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ if(add_count