/* * 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; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; import java.io.FileWriter; import org.openpixi.pixi.physics.collision.algorithms.CollisionAlgorithm; import org.openpixi.pixi.physics.collision.detectors.Detector; import org.openpixi.pixi.physics.fields.PoissonSolver; import org.openpixi.pixi.physics.force.CombinedForce; import org.openpixi.pixi.physics.force.SimpleGridForce; import org.openpixi.pixi.physics.grid.Grid; import org.openpixi.pixi.physics.grid.Interpolation; import org.openpixi.pixi.physics.grid.LocalInterpolation; import org.openpixi.pixi.physics.movement.ParticleMover; import org.openpixi.pixi.physics.movement.boundary.ParticleBoundaries; import org.openpixi.pixi.physics.movement.boundary.SimpleParticleBoundaries; import org.openpixi.pixi.physics.particles.Particle; import org.openpixi.pixi.physics.util.DoubleBox; import java.util.ArrayList; import java.util.List; public class Simulation { /** * Timestep */ public double tstep; /** * Width of simulated area */ private double width; /** * Height of simulated area */ private double height; private double speedOfLight; private double eps0; private double mu0; /** * Number of iterations in the non-interactive simulation. */ private int iterations; /** * Total number of steps simulated so far. */ public int tottime; /** * Total number of steps between spectral measurements. */ public int specstep; /** * File path to output files. */ private String filePath; /** * Contains all Particle2D objects */ public ArrayList<Particle> particles; public CombinedForce f; private ParticleMover mover; /** * Grid for dynamic field calculation */ public Grid grid; public Detector detector; public CollisionAlgorithm collisionalgorithm; /** * We can turn on or off the effect of the grid on particles by adding or * removing this force from the total force. */ private SimpleGridForce gridForce = new SimpleGridForce(); private boolean usingGridForce = false; public boolean relativistic = false; private ParticleGridInitializer particleGridInitializer = new ParticleGridInitializer(); private Interpolation interpolation; /** * solver for the electrostatic poisson equation */ private PoissonSolver poisolver; public Interpolation getInterpolation() { return interpolation; } public int getIterations() { return iterations; } public double getWidth() { return width; } public double getHeight() { return height; } public double getSpeedOfLight() { return speedOfLight; } public ParticleMover getParticleMover() { return mover; } /** * Constructor for non distributed simulation. */ public Simulation(Settings settings) { tstep = settings.getTimeStep(); width = settings.getSimulationWidth(); height = settings.getSimulationHeight(); speedOfLight = settings.getSpeedOfLight(); iterations = settings.getIterations(); tottime = 0; specstep = settings.getSpectrumStep(); filePath = settings.getFilePath(); relativistic = settings.getRelativistic(); eps0 = settings.getEps0(); mu0 = settings.getMu0(); // TODO make particles a generic list particles = (ArrayList<Particle>) settings.getParticles(); f = settings.getForce(); ParticleBoundaries particleBoundaries = new SimpleParticleBoundaries( new DoubleBox(0, width, 0, height), settings.getParticleBoundary()); mover = new ParticleMover( settings.getParticleSolver(), particleBoundaries, settings.getParticleIterator()); grid = new Grid(settings); if (settings.useGrid()) { turnGridForceOn(); } else { turnGridForceOff(); } poisolver = settings.getPoissonSolver(); interpolation = new LocalInterpolation( settings.getInterpolator(), settings.getParticleIterator()); particleGridInitializer.initialize(interpolation, poisolver, particles, grid); detector = settings.getCollisionDetector(); collisionalgorithm = settings.getCollisionAlgorithm(); prepareAllParticles(); clearFile(); } /** * Constructor for distributed simulation. Expects settings specific to the * local node => the simulation width and height as well as the number of * cells in y and x direction must pertain to local simulation not to the * global simulation. (No need to set poison solver and run * ParticleGridInitializer as it was already run on the master node). */ public Simulation(Settings settings, Grid grid, List<Particle> particles, ParticleBoundaries particleBoundaries, Interpolation interpolation) { this.tstep = settings.getTimeStep(); this.width = settings.getSimulationWidth(); this.height = settings.getSimulationHeight(); this.speedOfLight = settings.getSpeedOfLight(); this.iterations = settings.getIterations(); this.tottime = 0; this.specstep = settings.getSpectrumStep(); this.filePath = settings.getFilePath(); this.relativistic = settings.getRelativistic(); this.eps0 = settings.getEps0(); this.mu0 = settings.getMu0(); this.particles = (ArrayList<Particle>) particles; f = settings.getForce(); mover = new ParticleMover( settings.getParticleSolver(), particleBoundaries, settings.getParticleIterator()); this.grid = grid; if (settings.useGrid()) { turnGridForceOn(); } else { turnGridForceOff(); } this.interpolation = interpolation; detector = settings.getCollisionDetector(); collisionalgorithm = settings.getCollisionAlgorithm(); prepareAllParticles(); clearFile(); } public void turnGridForceOn() { if (!usingGridForce) { f.add(gridForce); usingGridForce = true; } if(!f.forces.contains(gridForce)){ f.add(gridForce); } } public void turnGridForceOff() { if (usingGridForce) { f.remove(gridForce); usingGridForce = false; } } /** * Runs the simulation in steps. (for interactive simulations) */ public void step() throws FileNotFoundException,IOException { if (continues()) { // Only write to file while simulation continues. writeToFile(tstep*tottime); if( (tottime % specstep) == 0) writeSpecFile(tottime); } particlePush(); detector.run(); collisionalgorithm.collide(detector.getOverlappedPairs(), f, mover.getSolver(), tstep); interpolation.interpolateToGrid(particles, grid, tstep); grid.updateGrid(tstep); interpolation.interpolateToParticle(particles, grid); tottime++; } /** * Whether the simulation should continue. * @return */ public boolean continues() { return tottime <= iterations; } /** * Runs the entire simulation at once. (for non-interactive simulations) */ public void run() throws FileNotFoundException,IOException { while (continues()) { step(); } } /** * Checks if the files are already existent and deletes them. */ public void clearFile() { File particlesfile = getOutputFile("particles_seq.txt"); boolean fileExists1 = particlesfile.exists(); if(fileExists1 == true) { particlesfile.delete(); } File gridfile = getOutputFile("cells_seq.txt"); boolean fileExists2 = gridfile.exists(); if(fileExists2 == true) { gridfile.delete(); } } /** * Get output file in correct subdirectory. * Create subdirectories if necessary. * @param filename * @return file */ public File getOutputFile(String filename) { // Default output path is // 'output/' + filePath + '/' + filename File fullpath = new File("output"); if(!fullpath.exists()) fullpath.mkdir(); fullpath = new File(fullpath, filePath); if(!fullpath.exists()) fullpath.mkdir(); return new File(fullpath, filename); } /** * Write the results to a txt file */ public void writeToFile(double time) throws IOException { //PrintWriter pw = new PrintWriter(new File("particles_seq.txt")); File file = getOutputFile("particles_seq.txt"); FileWriter pw = new FileWriter(file, true); double kinetic = 0; double kineticTotal = 0; RelativisticVelocity relvelocity = new RelativisticVelocity(1); if(time == 0) { pw.write("#time \t x \t y \t vx \t vy \t kinetic \t Ex \t Ey \t Bz"); pw.write("\n"); } else {} pw.write(time + "\t"); for (int i = 0; i < particles.size(); i++) { pw.write(particles.get(i).getX() + "\t"); pw.write(particles.get(i).getY() + "\t"); //pw.write(particles.get(i).getRadius() + "\n"); pw.write(particles.get(i).getVx() + "\t"); pw.write(particles.get(i).getVy() + "\t"); pw.write(relvelocity.calculateGamma(particles.get(i)) + "\t"); if(relativistic == false) {kinetic = particles.get(i).getMass()*(particles.get(i).getVx() * particles.get(i).getVx() + particles.get(i).getVy()*particles.get(i).getVy())/2;} else {kinetic = Math.sqrt(particles.get(i).getMass()*particles.get(i).getMass()*( particles.get(i).getVx() * particles.get(i).getVx() + particles.get(i).getVy()*particles.get(i).getVy() + 1) ); } pw.write(kinetic + "\t"); kineticTotal += kinetic; pw.write(particles.get(i).getEx() + "\t"); pw.write(particles.get(i).getEy() + "\t"); pw.write(particles.get(i).getBz() + "\t"); /*pw.write(particles.get(i).getAx() + "\n"); pw.write(particles.get(i).getAy() + "\n"); pw.write(particles.get(i).getMass() + "\n"); pw.write(particles.get(i).getCharge() + "\n"); pw.write(particles.get(i).getPrevX() + "\n"); pw.write(particles.get(i).getPrevY() + "\n"); pw.write(particles.get(i).getPrevPositionComponentForceX() + "\n"); pw.write(particles.get(i).getPrevPositionComponentForceY() + "\n"); pw.write(particles.get(i).getPrevTangentVelocityComponentOfForceX() + "\n"); pw.write(particles.get(i).getPrevTangentVelocityComponentOfForceY() + "\n"); pw.write(particles.get(i).getPrevNormalVelocityComponentOfForceX() + "\n"); pw.write(particles.get(i).getPrevNormalVelocityComponentOfForceY() + "\n"); pw.write(particles.get(i).getPrevBz() + "\n"); pw.write(particles.get(i).getPrevLinearDragCoefficient() + "\n");*/ } pw.write("\n"); pw.close(); file = getOutputFile("cells_seq.txt"); //pw = new PrintWriter(file); pw = new FileWriter(file, true); pw.write(time + "\t"); double SumRho = 0; double SumJx = 0; double SumJy = 0; double fieldEnergy = 0; double GaussLaw = 0; //int NumPoints = grid.getNumCellsX()*grid.getNumCellsY(); for (int i = 0; i < grid.getNumCellsX(); i++) { for (int j = 0; j < grid.getNumCellsY(); j++) { SumRho += grid.getCells()[i][j].getRho(); SumJx += grid.getCells()[i][j].getJx(); SumJy += grid.getCells()[i][j].getJy(); fieldEnergy += ( grid.getCells()[i][j].getBz()*grid.getCells()[i][j].getBz() + grid.getCells()[i][j].getEx()*grid.getCells()[i][j].getEx() + grid.getCells()[i][j].getEy()*grid.getCells()[i][j].getEy())/2; GaussLaw += (grid.getEx((i+1)%grid.getNumCellsX(), j) - grid.getEx(i, j)) / grid.getCellWidth() + (grid.getEy(i, (j+1)%grid.getNumCellsY()) - grid.getEy(i, j)) / grid.getCellHeight() - grid.getRho(i,j)*4*Math.PI; /*pw.write(grid.getCells()[i][j].getJx() + "\n"); pw.write(grid.getCells()[i][j].getJy() + "\n"); pw.write(grid.getCells()[i][j].getRho() + "\n"); pw.write(grid.getCells()[i][j].getPhi() + "\n"); pw.write(grid.getCells()[i][j].getEx() + "\n"); pw.write(grid.getCells()[i][j].getEy() + "\n"); pw.write(grid.getCells()[i][j].getBz() + "\n"); pw.write(grid.getCells()[i][j].getBzo() + "\n");*/ } } pw.write(kineticTotal + "\t"); pw.write(fieldEnergy + "\t"); pw.write(SumRho + "\t"); pw.write(SumJx + "\t"); pw.write(SumJy + "\t"); pw.write(GaussLaw + "\t"); pw.write(grid.getEy(grid.getNumCellsX()/2, grid.getNumCellsY()/2) + "\t"); pw.write(grid.getBz(grid.getNumCellsX()/2, grid.getNumCellsY()/2) + "\t"); pw.write("\n"); pw.close(); } public void writeSpecFile(int time) throws FileNotFoundException { File file = getOutputFile("spec" + time + ".txt"); PrintWriter sw = new PrintWriter(file); for (int i = 0; i < particles.size(); i++) { sw.write(i + "\t"); sw.write(particles.get(i).getX() + "\t"); sw.write(particles.get(i).getY() + "\t"); sw.write(particles.get(i).getVx() + "\t"); sw.write(particles.get(i).getVy() + "\t"); sw.write("\n"); } sw.close(); file = getOutputFile("snapshot" + time + ".txt"); PrintWriter snap = new PrintWriter(file); for (int i = 0; i < grid.getNumCellsXTotal(); i++) { for (int j = 0; j < grid.getNumCellsYTotal(); j++) { snap.write(i + "\t"); snap.write(j + "\t"); snap.write(grid.getCells()[i][j].getEy() + "\t"); snap.write(grid.getCells()[i][j].getBz() + "\t"); snap.write("\n"); } } snap.close(); } public void particlePush() { mover.push(particles, f, tstep); } public void prepareAllParticles() { mover.prepare(particles, f, tstep); } public void completeAllParticles() { mover.complete(particles, f, tstep); } }