/*
* 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 BorisDamped implements Solver{
public BorisDamped()
{
super();
}
/**
* Boris algorithm for implementing the electric and magnetic field.
* The damping is implemented with an error O(dt^2), the same error of accuracy that the algorithm has.
* 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 getLinearDragCoefficient = f.getLinearDragCoefficient(p);
double getMass = p.getMass();
// remember for complete()
p.setPrevPositionComponentForceX(getPositionComponentofForceX);
p.setPrevPositionComponentForceY(getPositionComponentofForceY);
p.setPrevBz(getBz);
p.setPrevLinearDragCoefficient(getLinearDragCoefficient);
//help coefficients for the dragging
double help1_coef = 1 - getLinearDragCoefficient * step / (2 * getMass);
double help2_coef = 1 + getLinearDragCoefficient * step / (2 * getMass);
double vxminus = help1_coef * p.getVx() / help2_coef + getPositionComponentofForceX * step / (2.0 * getMass * help2_coef);
double vyminus = help1_coef * p.getVy() / help2_coef + getPositionComponentofForceY * step / (2.0 * getMass * help2_coef);
double t_z = p.getCharge() * getBz * step / (2.0 * getMass * help2_coef); //t vector
double s_z = 2 * t_z / (1 + t_z * t_z); //s vector
double kappa = - 4 * getMass * getLinearDragCoefficient * step / (4 * getMass * getMass -
getLinearDragCoefficient * getLinearDragCoefficient * step * step);
double vxprime = vxminus + help2_coef * vyminus * t_z / help1_coef + kappa * step * getPositionComponentofForceY * t_z / (2.0 * getMass);;
double vyprime = vyminus - help2_coef * vxminus * t_z / help1_coef - kappa * step * getPositionComponentofForceX * t_z / (2.0 * getMass);;
double vxplus = vxminus + vyprime * s_z + (help2_coef / help1_coef - 1) * (vyminus * t_z + vxminus * t_z * t_z) / (1 + t_z * t_z) +
kappa * step * (getPositionComponentofForceY + getPositionComponentofForceX * t_z) * s_z / (4.0 * getMass);
double vyplus = vyminus - vxprime * s_z + (help2_coef / help1_coef - 1) * (- vxminus * t_z + vyminus * t_z * t_z) / (1 + t_z * t_z) -
kappa * step * (getPositionComponentofForceX - getPositionComponentofForceY * t_z) * s_z / (4.0 * getMass);
p.setVx(vxplus + getPositionComponentofForceX * step / (2.0 * getMass * help2_coef));
p.setVy(vyplus + getPositionComponentofForceY * step / (2.0 * getMass * help2_coef));
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 getLinearDragCoefficient = f.getLinearDragCoefficient(p);
double getMass = p.getMass();
// remember for complete()
p.setPrevPositionComponentForceX(getPositionComponentofForceX);
p.setPrevPositionComponentForceY(getPositionComponentofForceY);
p.setPrevBz(getBz);
p.setPrevLinearDragCoefficient(getLinearDragCoefficient);
double step = - dt * 0.5;
//help coefficients for the dragging
double help1_coef = 1 - getLinearDragCoefficient * step / (2 * getMass);
double help2_coef = 1 + getLinearDragCoefficient * step / (2 * getMass);
double vxminus = help1_coef * p.getVx() / help2_coef + getPositionComponentofForceX * step / (2.0 * getMass * help2_coef);
double vyminus = help1_coef * p.getVy() / help2_coef + getPositionComponentofForceY * step / (2.0 * getMass * help2_coef);
double t_z = p.getCharge() * getBz * step / (2.0 * getMass * help2_coef); //t vector
double s_z = 2 * t_z / (1 + t_z * t_z); //s vector
double kappa = - 4 * getMass * getLinearDragCoefficient * step / (4 * getMass * getMass -
getLinearDragCoefficient * getLinearDragCoefficient * step * step);
double vxprime = vxminus + help2_coef * vyminus * t_z / help1_coef + kappa * step * getPositionComponentofForceY * t_z / (2.0 * getMass);;
double vyprime = vyminus - help2_coef * vxminus * t_z / help1_coef - kappa * step * getPositionComponentofForceX * t_z / (2.0 * getMass);;
double vxplus = vxminus + vyprime * s_z + (help2_coef / help1_coef - 1) * (vyminus * t_z + vxminus * t_z * t_z) / (1 + t_z * t_z) +
kappa * step * (getPositionComponentofForceY + getPositionComponentofForceX * t_z) * s_z / (4.0 * getMass);
double vyplus = vyminus - vxprime * s_z + (help2_coef / help1_coef - 1) * (- vxminus * t_z + vyminus * t_z * t_z) / (1 + t_z * t_z) -
kappa * step * (getPositionComponentofForceX - getPositionComponentofForceY * t_z) * s_z / (4.0 * getMass);
p.setVx(vxplus + getPositionComponentofForceX * step / (2.0 * getMass * help2_coef));
p.setVy(vyplus + getPositionComponentofForceY * step / (2.0 * getMass * help2_coef));
}
/**
* 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 getPrevLinearDragCoefficient = p.getPrevLinearDragCoefficient();
double getMass = p.getMass();
double step = dt * 0.5;
//help coefficients for the dragging
double help1_coef = 1 - getPrevLinearDragCoefficient * step / (2 * getMass);
double help2_coef = 1 + getPrevLinearDragCoefficient * step / (2 * getMass);
double vxminus = help1_coef * p.getVx() / help2_coef + getPrevPositionComponentForceX * step / (2.0 * getMass * help2_coef);
double vyminus = help1_coef * p.getVy() / help2_coef + getPrevPositionComponentForceY * step / (2.0 * getMass * help2_coef);
double t_z = p.getCharge() * p.getPrevBz() * step / (2.0 * getMass * help2_coef); //t vector
double s_z = 2 * t_z / (1 + t_z * t_z); //s vector
double kappa = - 4 * getMass * getPrevLinearDragCoefficient * step / (4 * getMass * getMass -
getPrevLinearDragCoefficient * getPrevLinearDragCoefficient * step * step);
double vxprime = vxminus + help2_coef * vyminus * t_z / help1_coef + kappa * step * getPrevPositionComponentForceY * t_z / (2.0 * getMass);;
double vyprime = vyminus - help2_coef * vxminus * t_z / help1_coef - kappa * step * getPrevPositionComponentForceX * t_z / (2.0 * getMass);;
double vxplus = vxminus + vyprime * s_z + (help2_coef / help1_coef - 1) * (vyminus * t_z + vxminus * t_z * t_z) / (1 + t_z * t_z) +
kappa * step * (getPrevPositionComponentForceY + getPrevPositionComponentForceX * t_z) * s_z / (4.0 * getMass);
double vyplus = vyminus - vxprime * s_z + (help2_coef / help1_coef - 1) * (- vxminus * t_z + vyminus * t_z * t_z) / (1 + t_z * t_z) -
kappa * step * (getPrevPositionComponentForceX - getPrevPositionComponentForceY * t_z) * s_z / (4.0 * getMass);
p.setVx(vxplus + getPrevPositionComponentForceX * step / (2.0 * getMass * help2_coef));
p.setVy(vyplus + getPrevPositionComponentForceY * step / (2.0 * getMass * help2_coef));
}
}