/******************************************************************** * * * Compute particle motions for electron blobs leaving an * * electron source shaped like a sphere at either cusp or coil * * face locations. Every time step tracks more particles from * * source point and computes total electric and magnetic fields * * create from all previous sources as they interact with each * * other. * * * * Author = Mike Rosing * * date = March 12, 2008 * * * *******************************************************************/ #include #include #define MAXSTEPS 25 #define NUMELMNTS ((MAXSTEPS+1)*(MAXSTEPS+2)*(MAXSTEPS+3)/6) /* MAXBLOBS is the storage limit for electron blobs to follow */ #define MAXBLOBS 100000 /* MAXWALL is the ratio of outer containment sphere radius to L (center of sphere to center of coil distance) */ #define MAXWALL (3.0) /* COILRADIUS is the ratio of coil radius to L */ #define COILRADIUS (0.9) /* COILDIAMETER is the effective cross section of the coil, also in reference to L */ #define COILDIAMETER (0.01) /* ANGLEPS is the smallest allowed angle for a match. I set it fairly large, but it could also be a function of MAXSTEPS. */ #define ANGLEPS 1e-4 /* Cp is a constant that makes the fluid equation dimensionless. It turns out it this combination of constants happens a lot, and arises any where the magnetic field does. The formula for Cp is Cp^2 = 8*pi^2 * m * V / ( mu_0^2 * I_0^2 * e ) where m is electron mass, V is MaGrid potential, mu_0 is permiability of free space, I_0 is current in MaGrid coils and e is the charge on an electron. Thus the ratio of MaGrid voltage to square of current is an important factor in the system. */ #define CONST_CP (0.02) /* SOURCEPOSITION is distance from center of polywell to center of electron source sphere. It is in units of L. */ #define SOURCEPOSITION 2.6 /* SOURCERADIUS is the radius of the electron source, in units of L */ #define SOURCERADIUS 0.1 /* SOURCEROWS are the number of rows to use on the electron source. Total number of electron blobs will be SOURCEROWS*(SOURCEROWS+1)/2, but the number tracked will be 48 times that due to symmetry. */ #define SOURCEROWS 10 #define SOURCE_ELEMENTS (SOURCEROWS+1)*SOURCEROWS/2 /* SOURCEVOLTAGE is the negative voltage applied to the electron source. It is relative to the MaGrid voltage so that the actual voltage on the electron source is SOURCEVOLTAGE * V. */ #define SOURCEVOLTAGE (-0.1) /* MAXTIMESTEPS is the number of times to do the calculation loop EMISSIONTIME is the number of time steps to allow electrons to leave the electron source. */ #define MAXTIMESTEPS 10 #define EMISSIONTIME 5 /* DELTANU is the dimensionless time scale. It is DELTANU = e*mu0*I0/ ( 4*PI*m*L) * delta_t For 200k Ampturns, L = 1m, a value of DELTANU = 1 corresponds to 1/3 of a nanosecond. */ #define DELTANU (0.10) /* v0 is the velocity of the an electron accelerated to full MaGrid voltage assuming Newtonian energy transfer: v0 = sqrt(2*e*V/m) Since we need v0/(2*c) as a dimensionless parameter create BETA0 = (v0/2/c)^2 for use in magnetic field calculations. */ #define BETA0 (0.05) /* to follow electron blobs, save position, velocity and fields that act on it. valid bit tells me if the particle has hit the wall - the only purpose is to avoid garbage collection activity so this could be used to save memory. */ typedef struct { int valid; double r, thta, phi; double ux, uy, uz; double ex, ey, ez; double bx, by, bz; } Phase_Space; /* Create global buffers for data storage so integrals are easy */ double GridEfld[3*NUMELMNTS]; double SrcEfld[3*NUMELMNTS]; double MagFld[3*NUMELMNTS]; double ElcFld[3*NUMELMNTS]; int numangles[NUMELMNTS]; int GridCurrent[MAXTIMESTEPS]; int WallCurrent[MAXTIMESTEPS]; int SrcCurrent[MAXTIMESTEPS]; Phase_Space eblob[MAXBLOBS]; /* subroutine to copy phase space elements from one place to another. Enter with pointers to source and destination. Does not need to copy field values (yet). */ void copy_phase( Phase_Space *src, Phase_Space *dst) { dst->valid = src->valid; dst->r = src->r; dst->thta = src->thta; dst->phi = src->phi; dst->ux = src->ux; dst->uy = src->uy; dst->uz = src->uz; } /* Subroutine to find mirror points to phase space blobs. Enter with pointer to reflection plane normal vector, number of blobs to reflect and pointer to list of blobs. Extends list in place and returns total # of blobs. Need room for 48 blobs total. */ int mirror_phase( double *normal, int nblb, Phase_Space *phspnts) { int i, xtnd; double adotp, x, y, z, xprm, yprm, zprm, phick; xtnd = nblb; for(i=0; i k-b) *dexptr = (idex + k*(k+1)/2 + j - 1)*3; else *dexptr = (idex + kdex + jdex)*3; dexptr++; } } } } /* compute electric field generated by electron source on coil face. */ main() { FILE *readmag, *particles; int numread, dexptrs[8], numblobs, time; char filename[64], input[8]; double magpot_amp; double across, r, phi, theta; int err, numval, i, j, k, idex, jdex, dex; double pi4, alpha, beta; double rprime, thetaprime, phiprime; double temp1, temp2, t, dist, dtr, dmr; int ip, jp, kp, npts, np, edex, kdex, passnum, abdex; double dsum, sum, dr, temp, acp; int srcnum, blobdex; double mirror[6][3], srcangle, coildistance, tparamtop, tparambot; double emag, cp, ctm, ctp, xprime, yprime, zprime, px, py, pz; double cpsi1, cpsi2, spsi1, spsi2, psicntr, psi[SOURCEROWS+2]; double srcntr[(SOURCEROWS+1)*(SOURCEROWS+2)], rw, escale, bscale; double r0, r1, t00, t01, t10, t11, cp00, cp01, cp10, cp11; double ct00, ct01, ct10, ct11, st00, st01, st10, st11; double ex, ey, ez, bx, by, bz, w[8], r20, r21, rz; double dux, duy, duz, xb, yb, zb, xe, ye, ze; Phase_Space esrc[SOURCE_ELEMENTS], cpyblb[48]; /* load MaGrid electric field from previous calculation */ sprintf(filename, "e_field_25.dat"); readmag = fopen(filename, "rb"); if( !readmag) { printf("can't read in potential data file %s.\n", filename); exit(0); } printf("opening potential data files and reading them in.\n"); numread = fread(GridEfld, sizeof(double), 3*NUMELMNTS, readmag); if(numread < 3*NUMELMNTS) printf("\nWARNING: not all field file read in. \n\n"); fclose(readmag); /* load MaGrid magnetic field from previous calculation */ sprintf(filename, "b_field_25.dat"); readmag = fopen(filename, "rb"); if( !readmag) { printf("can't read in magnetic potential data file %s.\n", filename); exit(0); } printf("opening magnetic potential data files and reading them in.\n"); numread = fread(MagFld, sizeof(double), 3*NUMELMNTS, readmag); if(numread < 3*NUMELMNTS) printf("\nWARNING: not all field file read in. \n\n"); fclose(readmag); /* Compute constants for main calculations */ pi4 = M_PI/4.0; // ubiquitous constant srcangle = atan(SOURCERADIUS / SOURCEPOSITION); coildistance = sqrt(COILRADIUS*COILRADIUS + 1.0); tparamtop = MAXWALL - SOURCERADIUS; tparambot = SOURCEPOSITION*SOURCEPOSITION - tparamtop*tparamtop; emag = SOURCEVOLTAGE*SOURCERADIUS/tparamtop; emag *= MAXWALL; tparamtop *= SOURCERADIUS; /* compute electric field generated by electron source balls */ SrcEfld[0] = 0.0; SrcEfld[1] = 0.0; SrcEfld[2] = 0.0; dex = 3; for(i=1; i MAXWALL) { WallCurrent[time]++; eblob[idex].valid = 0; printf("blob %d has hit wall at %lf\n", idex,eblob[idex].r); continue; } temp1 = eblob[idex].r - coildistance; if(temp1<0.0) temp1 = -temp1; if(temp1 <= COILDIAMETER) { GridCurrent[time]++; eblob[idex].valid = 0; continue; } if((eblob[idex].thta <= srcangle) && (eblob[idex].phi <= srcangle)) { temp1 = 2.0*SOURCEPOSITION*eblob[idex].r; temp1 *= cos(eblob[idex].thta)*cos(eblob[idex].phi); temp1 = sqrt(rw + eblob[idex].r*eblob[idex].r - temp1); if(temp1 <= SOURCERADIUS) { SrcCurrent[time]++; eblob[idex].valid = 0; } } } } /* create new particles at sources if allowed */ if(time < EMISSIONTIME) { printf("begin emission\n"); for(j=0; j2) exit(0); */ } } } /* scale all E and B fields according to dimensionless formula */ printf("begin scaling\n\n\n"); for(dex=0; dexdex) k = dex; j = dex/pi4*eblob[blobdex].thta + 1; if( j>k) j = k; /* compute indicies and weights to neighbors of this point */ r0 = dex*MAXWALL/MAXSTEPS; r1 = (dex-1)*MAXWALL/MAXSTEPS; t00 = pi4/dex*j; t01 = pi4/dex*(j-1); t10 = pi4/(dex-1)*j; t11 = pi4/(dex-1)*(j-1); ct00 = cos(t00); st00 = sin(t00); ct01 = cos(t01); st01 = sin(t01); ct10 = cos(t10); st10 = sin(t10); ct11 = cos(t11); st11 = sin(t11); neighborhood(dex, j, k, dexptrs); r = eblob[blobdex].r; r20 = r*r; r21 = r20 + r1*r1; r20 += r0*r0; temp1 = cos(eblob[blobdex].thta); temp2 = sin(eblob[blobdex].thta); t = eblob[blobdex].phi; cp00 = cos(t - pi4/dex*k); cp01 = cos(t - pi4/dex*(k-1)); cp10 = cos(t - pi4/(dex-1)*k); cp11 = cos(t - pi4/(dex-1)*(k-1)); w[0] = r20 - r*r0*(temp1*ct00*cp00 + temp2*st00); w[1] = r20 - r*r0*(temp1*ct00*cp01 + temp2*st00); w[2] = r20 - r*r0*(temp1*ct01*cp00 + temp2*st01); w[3] = r20 - r*r0*(temp1*ct01*cp01 + temp2*st01); w[4] = r21 - r*r1*(temp1*ct10*cp10 + temp2*st10); w[5] = r21 - r*r1*(temp1*ct10*cp11 + temp2*st10); w[6] = r21 - r*r1*(temp1*ct11*cp10 + temp2*st11); w[7] = r21 - r*r1*(temp1*ct11*cp11 + temp2*st11); sum = 0.0; for(i=0; i<8; i++) sum += w[i]; ex = 0.0; ey = 0.0; ez = 0.0; bx = 0.0; by = 0.0; bz = 0.0; for(i=0; i<8; i++) { ex += ElcFld[dexptrs[i]]/w[i]; ey += ElcFld[dexptrs[i]+1]/w[i]; ez += ElcFld[dexptrs[i]+2]/w[i]; bx += MagFld[dexptrs[i]]/w[i]; by += MagFld[dexptrs[i]+1]/w[i]; bz += MagFld[dexptrs[i]+2]/w[i]; } ex *= sum; ey *= sum; ez *= sum; bx *= sum; by *= sum; bz *= sum; /* compute change in velocity of this particle based on electric and magnetic field it is exposed to. */ dux = eblob[blobdex].uy*(bz + eblob[blobdex].bz); dux -= eblob[blobdex].uz*(by + eblob[blobdex].by); dux /= CONST_CP; dux += ex + eblob[blobdex].ex; dux *= escale*DELTANU; duy = eblob[blobdex].uz*(bx + eblob[blobdex].bx); duy -= eblob[blobdex].ux*(bz + eblob[blobdex].bz); duy /= CONST_CP; duy += ey + eblob[blobdex].ey; duy *= escale*DELTANU; duz = eblob[blobdex].ux*(by + eblob[blobdex].by); duz -= eblob[blobdex].uy*(bx + eblob[blobdex].bx); duz /= CONST_CP; duz += ez + eblob[blobdex].ez; duz *= escale*DELTANU; /* move particle to new position */ eblob[blobdex].ux += dux; eblob[blobdex].uy += duy; eblob[blobdex].uz += duz; px = eblob[blobdex].r*cos(eblob[blobdex].thta); py = px*sin(eblob[blobdex].phi); px *= cos(eblob[blobdex].phi); pz = eblob[blobdex].r*sin(eblob[blobdex].thta); px += eblob[blobdex].ux*DELTANU; py += eblob[blobdex].uy*DELTANU; pz += eblob[blobdex].uz*DELTANU; r20 = px*px + py*py; eblob[blobdex].r = sqrt(r20 + pz*pz); phi = atan2(py, px); if(phi < 0.0) eblob[blobdex].phi = 2.0*M_PI + phi; else eblob[blobdex].phi = phi; eblob[blobdex].thta = atan(pz/sqrt(r20)); /* check to see if particle is outsize zone zero - swap it back if it is. Not exactly efficient, but goes through all possible combinations. */ if(eblob[blobdex].thta < 0.0) { eblob[blobdex].thta = -eblob[blobdex].thta; eblob[blobdex].uz = -eblob[blobdex].uz; } if(eblob[blobdex].phi > M_PI) { eblob[blobdex].phi = 2.0*M_PI - eblob[blobdex].phi; eblob[blobdex].uy = -eblob[blobdex].uy; } if(eblob[blobdex].phi > M_PI/2.0) { eblob[blobdex].phi = M_PI - eblob[blobdex].phi; eblob[blobdex].ux = -eblob[blobdex].ux; } if(eblob[blobdex].phi < eblob[blobdex].thta) { temp1 = eblob[blobdex].phi; eblob[blobdex].phi = eblob[blobdex].thta; eblob[blobdex].thta = temp1; temp1 = eblob[blobdex].uz; eblob[blobdex].uz = eblob[blobdex].uy; eblob[blobdex].uy = temp1; } if(eblob[blobdex].phi > M_PI/4.0) { if(eblob[blobdex].thta > M_PI/2.0 - eblob[blobdex].phi) { temp1 = eblob[blobdex].thta; eblob[blobdex].thta = M_PI/2.0 - eblob[blobdex].phi; eblob[blobdex].phi = M_PI/2.0 - temp1; temp1 = eblob[blobdex].uz; eblob[blobdex].uz = eblob[blobdex].ux; eblob[blobdex].ux = temp1; } eblob[blobdex].phi = M_PI/2.0 - eblob[blobdex].phi; temp1 = eblob[blobdex].uy; eblob[blobdex].uy = eblob[blobdex].ux; eblob[blobdex].ux = temp1; } /* printf("for particle %d we have:\n", blobdex); printf("r = %lf phi = %lf thta = %lf\n", eblob[blobdex].r, eblob[blobdex].phi, eblob[blobdex].thta); printf("ux = %lf uy = %lf uz = %lf\n", eblob[blobdex].ux, eblob[blobdex].uy, eblob[blobdex].uz); printf("ex = %lf ey = %lf ez = %lf\n", eblob[blobdex].ex, eblob[blobdex].ey, eblob[blobdex].ez); printf("bx = %lf by = %lf bz = %lf\n", eblob[blobdex].bx, eblob[blobdex].by, eblob[blobdex].bz); printf("\n"); */ }// blobdex /* save particle distibution to disk for later analysis */ printf("save particles to disk\n"); sprintf(filename, "particles_%03d.dat", time); particles = fopen(filename, "w"); if(!particles) { printf("can't create %s! \n", filename); exit(0); } fwrite(&time, sizeof(int), 1, particles); fwrite(&numblobs, sizeof(int), 1, particles); fwrite(WallCurrent, sizeof(int), time+1, particles); fwrite(GridCurrent, sizeof(int), time+1, particles); fwrite(SrcCurrent, sizeof(int), time+1, particles); fwrite(eblob, sizeof(Phase_Space), numblobs, particles); fclose(particles); }// time printf("done!\n"); }