This is the web version of EJS interface
EJS version 3.4
  1. AuxiliaryFiles=_examples/_data/charged.gif;_examples/_data/particles.gif;_examples/_data/paco.gif;_examples/_data/ParticlesAndWalls.gif;
    NameValueTypeDimension
    NameValueTypeDimension
    NameValueTypeDimension
    NameValueTypeDimension
    numParticles = 10; resistance = 0.01; for (int i=0; i<maxParticles; i++) { if (i%2==0) { type[i] = 1; size[i] = (maximum-minimum)/40.0; charge[i] = 1.0; color[i] = java.awt.Color.blue; } else { type[i] = 10; size[i] = (maximum-minimum)/50.0; charge[i] = -1.0; color[i] = java.awt.Color.red; } visible[i] = i<numParticles; x[i] = minimum + (maximum-minimum)*Math.random(); y[i] = minimum + (maximum-minimum)*Math.random(); double angle = 2.0*Math.PI*Math.random(); vx[i] = speed*(Math.random ()-0.5); vy[i] = speed*(Math.random ()-0.5); }
    double step = (maximum - minimum)/(resolution-1); for (int i=0; i<resolution; i++) { for (int j=0; j<resolution; j++) { field[i][j][0] = minimum + step*i; field[i][j][1] = minimum + step*j; potential[i][j][0] = minimum + step*i; potential[i][j][1] = minimum + step*j; } }
    Indep. Var. Increment
    d x[i] /dtime=vx[i]
    d y[i] /dtime=vy[i]
    d vx[i] /dtime=force(i,x,y,true)/mass[i]
    d vy[i] /dtime=force(i,x,y,false)/mass[i]
    SolverMidPoint

    Compute derived variables

    // Store previous positions in case of collision with walls for (int i=0; i<numParticles; i++) { xPrev[i] = x[i]; yPrev[i] = y[i]; } // compute the field computeVectorField (); computePotential (); computeField(newX,newY); // This needs to be the last one
    private double force(int particle, double a[], double b[], boolean xAxis) { double force = 0.0, r2; if (particle>=numParticles) return 0.0; for (int i=0; i<numParticles; i++) { if (i==particle) continue; r2 = (a[i]-a[particle])*(a[i]-a[particle]) + (b[i]-b[particle])*(b[i]-b[particle]); if (r2<threshold) continue; if (xAxis) force += K*charge[i]*charge[particle]*(a[particle]-a[i])/r2; else force += K*charge[i]*charge[particle]*(b[particle]-b[i])/r2; } return force; } private void computeField (double a, double b) { double force = 0.0, r2; Ex=0.0; Ey=0.0; for (int i=0; i<numParticles; i++) { r2 = (x[i]-a)*(x[i]-a) + (y[i]-b)*(y[i]-b); if (r2<threshold) continue; Ex += K*charge[i]*(a-x[i])/r2; Ey += K*charge[i]*(b-y[i])/r2; } } public void computeVectorField () { if (showVectorField) for (int i=0; i<resolution; i++) { for (int j=0; j<resolution; j++) { computeField(field[i][j][0],field[i][j][1]); double r=Math.sqrt(Ex*Ex+Ey*Ey); field[i][j][2] = Ex/r; field[i][j][3] = Ey/r; field[i][j][4] = r; } } } private double computePotential (double a, double b) { double pot = 0.0, r2; for (int i=0; i<numParticles; i++) { r2 = (x[i]-a)*(x[i]-a) + (y[i]-b)*(y[i]-b); if (r2<threshold) continue; pot -= K*charge[i]*Math.log(r2)*0.5; } return pot; } public void computePotential () { if (showPotential || showCheckerPotential || showPotential3D) for (int i=0; i<resolution; i++) { for (int j=0; j<resolution; j++) { potential[i][j][2] = computePotential(potential[i][j][0],potential[i][j][1]); } } } public void computePotentialExtrema () { if (!(showPotential || showCheckerPotential || showPotential3D)) { potentialMinimum = 0.0; potentialMaximum = 1.0; return; } computePotential(); double min = Double.MAX_VALUE; double max = Double.MIN_VALUE; for (int i=0; i<resolution; i++) { for (int j=0; j<resolution; j++) { min = Math.min (min,potential[i][j][2]); max = Math.max (max,potential[i][j][2]); } } potentialMinimum = min; potentialMaximum = max; }
    public void clearParticles () { for (int i=0; i<maxParticles; i++) { visible[i] = false; showVel[i] = false; } numParticles = 0; } public void freeze () { for (int i=0; i<maxParticles; i++) { vx[i] = 0.0; vy[i] = 0.0; } } public void collapse () { for (int i=0; i<maxParticles; i++) { x[i] = 0.0; y[i] = 0.0; vx[i] = speed*(Math.random ()-0.5); vy[i] = speed*(Math.random ()-0.5); } } public void showVelocities () { for (int i=0; i<numParticles; i++) showVel[i] = showSpeeds; } public void clearWalls () { for (int i=0; i<wallMaxPoints; i++) { wallVisible[i] = false; } wallNumPoints = 0; }
    public void addElements () { if (addPositive) for (int i=0; i<howMany; i++) addParticle (newX,newY,true); else if (addNegative) for (int i=0; i<howMany; i++) addParticle (newX,newY,false); else if (addWall) addWallPoint (newX,newY); } public void addWalls () { if (addWall) addWallPoint (newX,newY); } public void showField() { computeField(newX,newY); } private void addParticle (double a, double b, boolean positive) { if (numParticles>=maxParticles) return; int n = numParticles; x[n] = a; y[n] = b; vx[n] = speed*(Math.random ()-0.5); vy[n] = speed*(Math.random ()-0.5); if (positive) { type[n] = 1; size[n] = (maximum-minimum)/40.0; charge[n] = 1.0; color[n] = java.awt.Color.blue; } else { type[n] = 10; size[n] = (maximum-minimum)/50.0; charge[n] = -1.0; color[n] = java.awt.Color.red; } visible[n] = true; showVel[n] = showSpeeds; numParticles++; }
    void checkWallsIntersection (int index, double timeUsed, int lastWall) { int intWall=-1, endPoint=-1; double a1 = xPrev[index], b1 = yPrev[index]; double a2 = x[index], b2 = y[index]; double smallestT=1.0e10; double z1,z2,pa,pb,prod, t,va,vb; double z2Int=0.0, paInt=0.0, pbInt=0.0; for (int i=0; i<wallNumPoints; i++) { endPoint = wallConnectedTo[i]; if (endPoint<0) continue; if (i==lastWall) continue; z2 = wallDy[i]*a2 - wallDx[i]*b2 + wallC[i]; if (z2==0.0) continue; z1 = wallDy[i]*a1 - wallDx[i]*b1 + wallC[i]; // first condition: z1*z2<0 (or z1==0) if (z2>0.0) { if (z1>0.0) continue; } else if (z1<0.0) continue; va = (a2-a1)/timeUsed; vb= (b2-b1)/timeUsed; t = - z1/(wallDy[i]*va - wallDx[i]*vb); // second condition:intersection point is in the middle pa = a1 + t*va; pb = b1 + t*vb; prod = (wallX[i]-pa)*(wallX[endPoint]-pa) + (wallY[i]-pb)*(wallY[endPoint]-pb); if (prod>0.0) continue; if (t<smallestT) { // third condition: must be the first intersecting wall intWall = i; smallestT = t; paInt = pa; pbInt = pb; z2Int = z2; } } if (intWall<0) { x[index] = a2; y[index] = b2; } else { t = - z2Int / wallR2[intWall]; xPrev[index] = paInt; yPrev[index] = pbInt; x[index] = a2 + 2.0*wallDy[intWall]*t; y[index] = b2 - 2.0*wallDx[intWall]*t; timeUsed = timeUsed-smallestT; prod = (vx[index]*wallDy[intWall] - vy[index]*wallDx[intWall])/wallR2[intWall]; vx[index] -= 2.0* (1.0-wallAbsortion)*prod*wallDy[intWall]; vy[index] -= -2.0*(1.0-wallAbsortion)*prod*wallDx[intWall];; checkWallsIntersection (index, timeUsed,intWall); } }
    void addWallPoint (double a, double b) { if (wallNumPoints>=wallMaxPoints) return; if (wallNumPoints>0) { // Do not connect two points which are too close if ( (Math.abs(wallX [wallNumPoints-1] - a) + Math.abs(wallY[wallNumPoints-1] - b)) < wallMinDistance) return; } int existingPoint = getWallPoint (a,b); if (existingPoint>=0) { a = wallX[existingPoint]; b = wallY[existingPoint]; } wallNumPoints++; int thisPoint = wallNumPoints-1; // Just for readability wallX [thisPoint] = a; wallY[thisPoint] = b; wallConnectedTo[thisPoint] = -1; if (thisPoint>0 && !wallStartNewOne) { wallConnectedTo[thisPoint-1] = thisPoint; setWall (thisPoint-1); } wallStartNewOne = (existingPoint>=0); } void setWall (int i) { int endPoint = wallConnectedTo[i]; wallVisible[i] = true; if (endPoint>=0) { wallDx[i] = wallX[endPoint]-wallX[i]; wallDy[i] = wallY[endPoint]-wallY[i]; wallC[i] = wallY[i]*wallX[endPoint] - wallX[i]*wallY[endPoint]; wallR2[i] = wallDx[i]*wallDx[i] + wallDy[i]*wallDy[i]; } } int getWallPoint (double a, double b) { double tolerance = (maximum-minimum) / 50.0; double distance; int found = -1; for (int i=0; i<wallNumPoints; i++) { // For each wall test both end-points (Yes, I know it is repetitive) if (wallVisible[i]==false) continue; distance = Math.abs(wallX[i]-a) + Math.abs(wallY[i]-b); if (distance<tolerance) { found = i; tolerance = distance; } if (wallConnectedTo[i]<0) continue; distance = Math.abs(wallX[wallConnectedTo[i]]-a) + Math.abs(wallY[wallConnectedTo[i]]-b); if (distance<tolerance) { found = wallConnectedTo[i]; tolerance = distance; } } return found; }
    public void saveFile () { _saveState(filename); } public void readFile () { _readState(filename); }
    EJSVIEW: Click link to view it's content
    Control variables:(testing)
    double,double
    title=Particles and Walls
    layout=border
    visible=true
    size="621,311"
    position=west
    layout=border
    position=north
    layout=grid:0,1,0,0
    text=Play
    enabled=_isPaused
    action=_play()
    text=Pause
    enabled=_isPlaying
    action=_pause()
    text=Step
    enabled=_isPaused
    action=_step()
    text=Reset
    action=_reset()
    text=Freeze
    action=freeze()
    text=Collapse
    action=collapse()
    variable=showSpeeds
    text=Velocities
    action=showVelocities()
    variable=showVectorField
    text=Vector Field
    action=computeVectorField()
    variable=showPotential
    text=Contour
    action=computePotentialExtrema()
    variable=showCheckerPotential
    selected=false
    text=Checker view
    action=computePotentialExtrema()
    variable=showPotential3D
    selected=false
    text=3D view
    action=computePotentialExtrema()
    position=east
    layout=border
    position=north
    layout=grid:0,2,0,0
    variable=numParticles
    format=Particles = 0
    editable=false
    variable=howMany
    format=Add 0
    position=center
    variable=addPositive
    text=Positive
    mnemonic=P
    variable=addNegative
    text=Negative
    mnemonic=N
    variable=addWall
    text=Build Wall
    mnemonic=W
    variable=showField
    text=Show Field
    mnemonic=F
    action=computeVectorField()
    text=No Parts
    action=clearParticles()
    text=No Walls
    action=clearWalls()
    text=Save
    action=saveFile()
    text=Read
    action=readFile()
    position=south
    layout=grid:0,1,0,0
    variable=resistance
    minimum=0.0
    maximum=0.2
    format=Res = 0.000
    ticks=9
    ticksFormat=0.##
    size=150,70
    variable=wallAbsortion
    minimum=0.0
    maximum=1.0
    format=Wall Absortion = 0.00
    ticks=9
    ticksFormat=0.#
    position=center
    layout=border
    position=north
    layout=border
    position=center
    variable=filename
    font=Dialog,PLAIN,14
    position=center
    autoscaleX=false
    autoscaleY=false
    minimumX=minimum
    maximumX=maximum
    minimumY=minimum
    maximumY=maximum
    x=newX
    y=newY
    dragaction=addWalls()
    action=addElements()
    data=potential
    autoscaleZ=false
    minimumZ=potentialMinimum
    maximumZ=potentialMaximum
    levels=21
    colormode=spectrum
    visible=showPotential
    data=potential
    minimumZ=potentialMinimum
    maximumZ=potentialMaximum
    levels=21
    colormode=spectrum
    visible=showCheckerPotential
    data=field
    autoscale=false
    minimum=0
    maximum=7
    levels=16
    mincolor=blue
    maxcolor=red
    zoom=5
    visible=showVectorField
    elementnumber=maxParticles
    x=x
    y=y
    sizex=size
    sizey=size
    visible=visible
    style=FILLED_CIRCLE
    elementposition=CENTERED
    color=color
    elementnumber=wallMaxPoints
    x=wallX
    y=wallY
    sizex=wallDx
    sizey=wallDy
    visible=wallVisible
    enabled=false
    style=SEGMENT
    color=black
    elementnumber=maxParticles
    x=x
    y=y
    sizex=vx
    sizey=vy
    scalex=5.0
    scaley=5.0
    visible=showVel
    style=ARROW
    color=pink
    x=newX
    y=newY
    sizex=Ex
    sizey=Ey
    scalex=20.0
    scaley=20.0
    visible=showField
    enabled=false
    style=ARROW
    color=64,128,0
    layout=border
    visible=showPotential3D
    location=100,100
    size=309,319
    position=center
    autoscaleX=false
    autoscaleY=false
    minimumX=-1.0
    maximumX=1.0
    minimumY=-1.0
    maximumY=1.0
    data=potential
    autoscaleZ=false
    minimumZ=potentialMinimum
    maximumZ=potentialMaximum
    visible=showPotential3D