package org.openpixi.pixi.physics.fields;

import edu.emory.mathcs.jtransforms.fft.DoubleFFT_2D;
import junit.framework.TestCase;
import org.openpixi.pixi.physics.Settings;
import org.openpixi.pixi.physics.Simulation;
import org.openpixi.pixi.physics.grid.ChargeConservingCIC;
import org.openpixi.pixi.physics.grid.Grid;

public class PoissonSolverTest extends TestCase {

	private double ACCURACY_LIMIT = 1.e-5;
	private Simulation s;
	private Grid g;
	private PoissonSolver poisolver;

	/**Tests whether the Poisson Euation is solved correctly for
	 * different charge distributions by comparing the output of
	 * the PoissonSolver to the analytic result.
	 */
	public PoissonSolverTest(String testName){
		super(testName);

		Settings stt = new Settings();
		stt.setSimulationWidth(10);
		stt.setSimulationHeight(10);
		stt.setGridSolver(new SimpleSolver());
		stt.setInterpolator(new ChargeConservingCIC());
		
		this.s = new Simulation(stt);
		this.g = s.grid;
		this.g.resetCurrent();
		
		this.poisolver = new PoissonSolverFFTPeriodic();
	}

	public void testPointchargeDistribution() {	
		//saves charge distribution in g.rho, includes specific test
		//for this charge distribution
		ChargeDistribution charged = new PointChargeDistributionCenter(g.getNumCellsX(), g.getNumCellsY());
		//solves poisson equation
		poisolver.solve(g);
		//compares with analytic result

		// TODO: Test does not work:
//		charged.test();
	}
	
	private interface ChargeDistribution {			
		/**Tests PoisonSolver and the analytic results*/
		void test();
	}
	
	private class PointChargeDistributionCenter implements ChargeDistribution {
		
		int indexX;
		int indexY;
		
		PointChargeDistributionCenter (int numCellsX, int numCellsY) {
			int indexX = numCellsX/2;
			int indexY = numCellsY/2;
			g.setRho(indexX, indexY, 1);
		}
		
		public void test() {
			assertEquals(g.getPhi(indexX, indexY)/(g.getCellWidth()), g.getPhi(indexX+1, indexY), ACCURACY_LIMIT);
		}
		
	}

	public void testFFT() {

		DoubleFFT_2D fft = new DoubleFFT_2D(10,10);
		double[][] field = new double[10][20];

		for (int i = 0; i < 10; i++) {
			for (int j = 0; j < 20; j++) {
				field[i][j] = 0;
			}
		}

		fft.complexForward(field);

	}
	
	void assertAlmostEquals(String text, double x, double y, double limit) {
		if ((Math.abs(x - y) / Math.abs(x + y) > limit)
				|| (Double.isNaN(x) != Double.isNaN(y))
				|| (Double.isInfinite(x) != Double.isInfinite(y))) {
			assertTrue(text + " expected:<" + x + "> but was:<" + y + ">", false);
		}
	}
}
