/* streetcar.c -- a program to simulate a disordered streetcar route by Jeffrey S. Rosenthal, 2007 */ #include #include #include #include #include #define DATACHOICE 0 #define LEADTIME 24.0 #define NUMCARSPER (28) /* per unit route length */ #define ROUTELENGTH 3 #define NUMCARS (NUMCARSPER * ROUTELENGTH) #define NUMREPS 10 #define NUMSIMS 1000 #define SIGMA 0.01 #define DELTA 0.0005 #define DIAMETER (0.05/NUMCARSPER) #define EPSILON (1.0/60/2) /* #define EPSILON DIAMETER */ #define MAXTIMES 1000 double dsfactor; #define DISPLAYLEVEL 2 /* #define STREETCARFLAG true */ #define STREETCARFLAG true /* #define RANDVEL true */ #define RANDVEL true #define PI 3.1415926536 #define SCREENWIDTH 80 main(argc, argv) int argc; char *argv[]; { double pos[NUMCARS], vel[NUMCARS]; double upper, nextvel; double min(), max(), normal(), reflection(), drand48(), sq(); double time[MAXTIMES], timeuntil, timesince, prevtime; int i, j, itnum, done, timenum, counting, spacenum, carcount, PRINTLENGTH; int simcount, simnum, numepss, numepsu, numepseps; int sumpass, sumtimes; double sumsince, sumuntil, sssince, ssuntil, sumprod, thetime, y; double meansince, meanuntil, meanprod, cov; double meansqsince, meansquntil, sdsince, sduntil, corr; double fracepsu, fracepseps; double begintime, endtime; struct timeval tmptv; /* Initialisations. */ seedrnd(); dsfactor = sqrt(DELTA) * SIGMA; simcount = 0; sumsince = sumuntil = sumprod = sssince = ssuntil = 0.0; sumpass = sumtimes = numepss = numepsu = numepseps = 0; PRINTLENGTH = 10; if (LEADTIME*NUMREPS/DELTA >= 1000000) PRINTLENGTH = 1; /* Start up. */ printf("\nBeginning %d reps of", NUMREPS); if (DATACHOICE==0) { printf(" %d sims of %.1f hrs of %d", NUMSIMS, LEADTIME+1, NUMCARS); #ifdef STREETCARFLAG printf(" streetcars (diam=%f)", DIAMETER); #else printf(" buses"); #endif } else { printf(" data set #%d.", DATACHOICE); } printf("\n"); gettimeofday (&tmptv, (struct timezone *)NULL); begintime = 1.0 * tmptv.tv_sec + 0.000001 * tmptv.tv_usec; /* Do the repeated simulations. */ for (j=0; j=0; i--) { #ifdef RANDVEL vel[i] = reflection( vel[i] + dsfactor * normal() ); #endif pos[i] = pos[i] + DELTA * vel[i]; #ifdef STREETCARFLAG /* Compute upper, etc. */ if (i==NUMCARS-1) { upper = pos[0]; nextvel = vel[0]; } else { upper = pos[i+1]; nextvel = vel[i+1]; } if (upper < pos[i]) upper = upper + ROUTELENGTH; upper = upper - DIAMETER; /* Slow down if reached upper. */ if (pos[i] > upper) { #ifdef VERBOSE printf("REDUCING pos[%d] from %f to %f!\n", i, pos[i], upper); #endif pos[i] = upper; vel[i] = min( vel[i], nextvel ); } #endif /* Check for cars "over the edge". */ if (pos[i] >= 0.0) { pos[i] = pos[i] - ROUTELENGTH; sumpass++; if (counting==0) { prevtime = DELTA * itnum; } else { time[timenum] = itnum * DELTA - LEADTIME; timenum++; sumtimes++; if (itnum * DELTA >= LEADTIME + 1.0) { done = 1; } } } } /* End of "i" for loop. */ if( (DISPLAYLEVEL>=4) || ( (DISPLAYLEVEL>=2) && (divisible(itnum,10000)) ) || ( (DISPLAYLEVEL>=1) && (done==1) ) ) { for (spacenum=0; spacenum=4) usleep(20000); } if ( (counting==0) && (itnum * DELTA >= LEADTIME) ) { /* Start counting arrival times. */ counting = 1; time[timenum] = prevtime - LEADTIME; timenum++; } itnum++; } /* End of "while" loop. */ if (DISPLAYLEVEL >= 2) { printf("\nEND OF ITERATION %d. %d ARRIVAL TIMES.\n", j, timenum); if (DISPLAYLEVEL >= 3) { for (i=0; i= 0) && (thetime < timeuntil) ) timeuntil = thetime; if ( (-thetime >= 0) && (-thetime < timesince) ) timesince = -thetime; } simcount++; sumsince = sumsince + timesince; sumuntil = sumuntil + timeuntil; sssince = sssince + sq(timesince); ssuntil = ssuntil + sq(timeuntil); sumprod = sumprod + timesince * timeuntil; if ( timeuntil < EPSILON ) numepsu++; if ( timesince < EPSILON ) { numepss++; if ( timeuntil < EPSILON ) numepseps++; } } /* Output this trial's results to stdout. */ if ( (DISPLAYLEVEL >= 1) || (divisible(j, PRINTLENGTH)) ) { printf("%4d / %d: sumuntil = %f, sumsince = %f\n", j+1, NUMREPS, sumuntil, sumsince); } } /* End of "j" for loop. */ /* Wrap up. */ printf("\nDone: %d reps of", NUMREPS); if (DATACHOICE==0) { printf(" %d sims of %.1f hrs of %d", NUMSIMS, LEADTIME+1, NUMCARS); #ifdef STREETCARFLAG printf(" streetcars (diam=%f)", DIAMETER); #else printf(" buses"); #endif } else { printf(" data set #%d.", DATACHOICE); } printf("\n"); printf("NUMCARSPER=%d, SIGMA=%f, DELTA=%f\n", NUMCARSPER, SIGMA, DELTA); gettimeofday (&tmptv, (struct timezone *)NULL); endtime = 1.0 * tmptv.tv_sec + 0.000001 * tmptv.tv_usec; /* Final output. */ printf("meannumpass=%.1f, meannumtimes=%.1f, ellapsed time = %.2f secs.\n", ((double)sumpass)/NUMREPS, ((double)sumtimes)/NUMREPS, endtime-begintime); meansince = sumsince/simcount; meanuntil = sumuntil/simcount; meanprod = sumprod/simcount; meansqsince = sssince/simcount; meansquntil = ssuntil/simcount; sdsince = sqrt(meansqsince - sq(meansince)); sduntil = sqrt(meansquntil - sq(meanuntil)); cov = meanprod - meansince*meanuntil; corr = cov / sdsince / sduntil; printf("meansince = %f, meanuntil = %f, meanprod = %f\n", meansince, meanuntil, meanprod); printf("meansqsince = %f, meansquntil = %f,\nsdsince = %f, sduntil = %f\n", meansqsince, meansquntil, sdsince, sduntil); printf("cov = %f, corr = %f\n", cov, corr); fracepsu = ((double)numepsu)/simcount; fracepseps = ((double)numepseps)/numepss; printf("fracepsu=%f, fracepseps=%f, perc=%f (eps=%f)\n", fracepsu, fracepseps, 100.0 * fracepseps / fracepsu, EPSILON ); printf("\n"); return(0); } /* REFLECTION -- reflect aa to be within [0,1] */ double reflection(double aa) { double reflection(); if (aa > 1.0) return( reflection(2.0 - aa) ); else if (aa < 0.0) return( reflection(- aa) ); else return( aa ); } /* PRINTTHECHAR */ printthechar(int nn) { if (nn==0) printf(" "); else if (nn==1) printf("|"); else if (nn==2) printf("+"); else if (nn==3) printf("X"); else printf("*"); } /* NORMAL: return a standard normal random number. */ double normal() { double R, theta, drand48(); R = - log(drand48()); theta = 2 * PI * drand48(); return( sqrt(2*R) * cos(theta)); } /* SEEDRND. */ seedrnd() { int seed; struct timeval tmptv; gettimeofday (&tmptv, (struct timezone *)NULL); seed = (int) (tmptv.tv_usec - 1000000 * ifloor ( ( (double) tmptv.tv_usec ) / ( (double) 1000000.0 ) ) ); srand48(seed); } /* IFLOOR */ int ifloor(double x) /* returns floor(x) as an integer */ { return((int)floor(x)); } /* SQ */ double sq(double xxx) { return(xxx * xxx); } /* MIN */ double min(double aa, double bb) { if (aa < bb) return(aa); return(bb); } /* DIVISIBLE */ int divisible (int n1, int n2) /* Check if n1 is divisible by n2. */ { return (n1 == n2 * (n1/n2)); }