/*
* OpenPixi - Open Particle-In-Cell (PIC) Simulator
* Copyright (C) 2012 OpenPixi.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.openpixi.pixi.physics.solver;
import org.openpixi.pixi.physics.*;
import org.openpixi.pixi.physics.force.Force;
import org.openpixi.pixi.physics.particles.Particle;
/**The calculation is due to Boris and the equations((7) - (10)) can be found here:
* http://ptsg.eecs.berkeley.edu/publications/Verboncoeur2005IOP.pdf
*/
public class Boris implements Solver{
public Boris()
{
super();
}
/**
* Boris algorithm for implementing the electric and magnetic field.
* The damping is implemented with an linear error O(dt).
* Warning: the velocity is stored half a time step before of the position.
* @param p before the update: x(t), v(t-dt/2);
* after the update: x(t+dt), v(t+dt/2)
*/
public void step(Particle p, Force f, double step) {
double getPositionComponentofForceX = f.getPositionComponentofForceX(p);
double getPositionComponentofForceY = f.getPositionComponentofForceY(p);
double getBz = f.getBz(p);
double getTangentVelocityComponentOfForceX = f.getTangentVelocityComponentOfForceX(p);
double getTangentVelocityComponentOfForceY = f.getTangentVelocityComponentOfForceY(p);
double getMass = p.getMass();
// remember for complete()
p.setPrevPositionComponentForceX(getPositionComponentofForceX);
p.setPrevPositionComponentForceY(getPositionComponentofForceY);
p.setPrevBz(getBz);
p.setPrevTangentVelocityComponentOfForceX(getTangentVelocityComponentOfForceX);
p.setPrevTangentVelocityComponentOfForceY(getTangentVelocityComponentOfForceY);
double vxminus = p.getVx() + getPositionComponentofForceX * step / (2.0 * getMass);
double vyminus = p.getVy() + getPositionComponentofForceY * step / (2.0 * getMass);
double t_z = p.getCharge() * getBz * step / (2.0 * getMass); //t vector
double s_z = 2 * t_z / (1 + t_z * t_z); //s vector
double vxprime = vxminus + vyminus * t_z;
double vyprime = vyminus - vxminus * t_z;
double vxplus = vxminus + vyprime * s_z;
double vyplus = vyminus - vxprime * s_z;
p.setVx(vxplus + getPositionComponentofForceX * step / (2.0 * getMass) + getTangentVelocityComponentOfForceX * step / getMass);
p.setVy(vyplus + getPositionComponentofForceY * step / (2.0 * getMass) + getTangentVelocityComponentOfForceY * step / getMass);
p.setX(p.getX() + p.getVx() * step);
p.setY(p.getY() + p.getVy() * step);
}
/**
* prepare method for bringing the velocity in the desired half step
* @param p before the update: v(t);
* after the update: v(t-dt/2)
*/
public void prepare(Particle p, Force f, double dt)
{
double getPositionComponentofForceX = f.getPositionComponentofForceX(p);
double getPositionComponentofForceY = f.getPositionComponentofForceY(p);
double getBz = f.getBz(p);
double getTangentVelocityComponentOfForceX = f.getTangentVelocityComponentOfForceX(p);
double getTangentVelocityComponentOfForceY = f.getTangentVelocityComponentOfForceY(p);
double getMass = p.getMass();
// remember for complete()
p.setPrevPositionComponentForceX(getPositionComponentofForceX);
p.setPrevPositionComponentForceY(getPositionComponentofForceY);
p.setPrevBz(getBz);
p.setPrevTangentVelocityComponentOfForceX(getTangentVelocityComponentOfForceX);
p.setPrevTangentVelocityComponentOfForceY(getTangentVelocityComponentOfForceY);
double step = -0.5 * dt;
double vxminus = p.getVx() + getPositionComponentofForceX * step / (2.0 * getMass) + getTangentVelocityComponentOfForceX * step / getMass;
double vyminus = p.getVy() + getPositionComponentofForceY * step / (2.0 * getMass) + getTangentVelocityComponentOfForceY * step / getMass;
double t_z = p.getCharge() * getBz * step / (2.0 * getMass); //t vector
double s_z = 2 * t_z / (1 + t_z * t_z); //s vector
double vxprime = vxminus + vyminus * t_z;
double vyprime = vyminus - vxminus * t_z;
double vxplus = vxminus + vyprime * s_z;
double vyplus = vyminus - vxprime * s_z;
p.setVx(vxplus + getPositionComponentofForceX * step / (2.0 * getMass));
p.setVy(vyplus + getPositionComponentofForceY * step / (2.0 * getMass));
}
/**
* complete method for bringing the velocity in the desired half step
* @param p before the update: v(t-dt/2);
* after the update: v(t)
*/
public void complete(Particle p, Force f, double dt)
{
double getPrevPositionComponentForceX = p.getPrevPositionComponentForceX();
double getPrevPositionComponentForceY = p.getPrevPositionComponentForceY();
double getMass = p.getMass();
dt = dt * 0.5;
double vxminus = p.getVx() + getPrevPositionComponentForceX * dt / (2.0 * getMass);
double vyminus = p.getVy() + getPrevPositionComponentForceY * dt / (2.0 * getMass);
double t_z = p.getCharge() * p.getPrevBz() * dt / (2.0 * getMass); //t vector
double s_z = 2 * t_z / (1 + t_z * t_z); //s vector
double vxprime = vxminus + vyminus * t_z;
double vyprime = vyminus - vxminus * t_z;
double vxplus = vxminus + vyprime * s_z;
double vyplus = vyminus - vxprime * s_z;
p.setVx(vxplus + getPrevPositionComponentForceX * dt / (2.0 * getMass) + p.getPrevTangentVelocityComponentOfForceX() * dt / getMass);
p.setVy(vyplus + getPrevPositionComponentForceY * dt / (2.0 * getMass) + p.getPrevTangentVelocityComponentOfForceY() * dt / getMass);
}
}