package org.openpixi.pixi.physics;
import org.openpixi.pixi.diagnostics.methods.Diagnostics;
import org.openpixi.pixi.parallel.cellaccess.CellIterator;
import org.openpixi.pixi.parallel.cellaccess.ParallelCellIterator;
import org.openpixi.pixi.parallel.cellaccess.SequentialCellIterator;
import org.openpixi.pixi.parallel.particleaccess.ParallelParticleIterator;
import org.openpixi.pixi.parallel.particleaccess.ParticleIterator;
import org.openpixi.pixi.parallel.particleaccess.SequentialParticleIterator;
import org.openpixi.pixi.physics.collision.algorithms.CollisionAlgorithm;
import org.openpixi.pixi.physics.collision.detectors.Detector;
import org.openpixi.pixi.physics.fields.FieldSolver;
import org.openpixi.pixi.physics.fields.PoissonSolver;
import org.openpixi.pixi.physics.fields.PoissonSolverFFTPeriodic;
import org.openpixi.pixi.physics.fields.SimpleSolver;
import org.openpixi.pixi.physics.force.CombinedForce;
import org.openpixi.pixi.physics.force.Force;
import org.openpixi.pixi.physics.grid.CloudInCell;
import org.openpixi.pixi.physics.grid.GridBoundaryType;
import org.openpixi.pixi.physics.grid.InterpolatorAlgorithm;
import org.openpixi.pixi.physics.movement.boundary.ParticleBoundaryType;
import org.openpixi.pixi.physics.particles.Particle;
import org.openpixi.pixi.physics.particles.ParticleFactory.PositionDistribution;
import org.openpixi.pixi.physics.particles.ParticleFactory.VelocityDistribution;
import org.openpixi.pixi.physics.solver.Euler;
import org.openpixi.pixi.physics.solver.Solver;
import org.openpixi.pixi.physics.util.ClassCopier;
import org.openpixi.pixi.physics.particles.ParticleFactory;
import org.openpixi.pixi.physics.particles.ParticleLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static org.openpixi.pixi.physics.GeneralBoundaryType.Hardwall;
import static org.openpixi.pixi.physics.GeneralBoundaryType.Periodic;
import org.openpixi.pixi.physics.grid.ChargeConservingCIC;
/**
* Specifies default values of simulation parameters. The default values can be
* overridden with a settings file input. The default values can be overridden
* with a command line input. The default values can be overridden
* programatically.
*
* NOTICE ON USAGE: To assure that the class is used in the intended way THE
* SETTERS SHOULD BE CALLED RIGHT AFTER A PARAMETERLESS CONSTRUCTOR AND BEFORE
* ANY OF THE MORE COMPLEX GETTERS IS CALLED !!!
*
* In the tests of the distributed version we pass the same settings class to
* all the different threads which simulate the distributed behaviour.
* Consequently, the different simultaneously running simulations do have the
* same particle solver, interpolator etc. and this is very dangerous. TODO
* ensure that all the getters retrieve new objects
*/
public class Settings {
//----------------------------------------------------------------------------------------------
// DEFAULT VALUES
//----------------------------------------------------------------------------------------------
private double speedOfLight = 1;
private double timeStep = 1;
private double gridStep = 1;
private double tMax = 3000;
private int spectrumStep = 300;
private String filePath = "default";
private GeneralBoundaryType boundaryType = GeneralBoundaryType.Periodic;
private InterpolatorAlgorithm interpolator = new ChargeConservingCIC();
//private InterpolatorAlgorithm interpolator = new CloudInCell();
// Grid related settings
private int gridCellsX = 10;
private int gridCellsY = 10;
private double simulationWidth = gridCellsX*gridStep;
private double simulationHeight = gridCellsY*gridStep;
private FieldSolver gridSolver = new SimpleSolver();
private PoissonSolver poissonSolver = new PoissonSolverFFTPeriodic();
private boolean useGrid = true;
private boolean relativistic = false;
private double eps0 = 1.0/(4*Math.PI);
private double mu0 = 4*Math.PI;
// Particle related settings
private int numOfParticles = 128;
private double particleRadius = 1;
private double particleMaxSpeed = speedOfLight / 3;
private int simulationType = 0;
private int writeToFile = 0;
private String OCLParticleSolver;
private String OCLGridInterpolator;
// Modify defaultParticleFactories() method to determine what kind of particles
// will be loaded by default.
private List<Particle> particles = new ArrayList<Particle>();
private Detector collisionDetector = new Detector();
private CollisionAlgorithm collisionResolver = new CollisionAlgorithm();
private Solver particleSolver = new Euler();
private List<Force> forces = new ArrayList<Force>();
// Diagnostics related settings
/**
* Used to mark output files
*/
private String runid = "default-run";
private List<Diagnostics> diagnostics = new ArrayList<Diagnostics>();
// Batch version settings
private int iterations = (int) Math.ceil(tMax/timeStep);
// Parallel (threaded) version settings
private int numOfThreads = 1;
/* The creation and start of the new threads is expensive. Therefore, in the parallel
* simulation we use ExecutorService which is maintaining a fixed number of threads running
* all the time and assigns work to the threads on the fly according to demand. */
private ExecutorService threadsExecutor;
// Distributed version settings
private int numOfNodes = 1;
private String iplServer = "localhost";
private String iplPool = "openpixi";
//----------------------------------------------------------------------------------------------
// SIMPLE GETTERS
//----------------------------------------------------------------------------------------------
public int getSimulationType() {
return this.simulationType;
}
public int getWriteToFile() {
return this.writeToFile;
}
public double getSimulationWidth() {
return simulationWidth;
}
public double getSimulationHeight() {
return simulationHeight;
}
public int getGridCellsX() {
return gridCellsX;
}
public int getGridCellsY() {
return gridCellsY;
}
public double getGridStep() {
return gridStep;
}
public int getSpectrumStep() {
return spectrumStep;
}
public String getFilePath() {
return filePath;
}
public boolean getRelativistic() {
return relativistic;
}
public double getSpeedOfLight() {
return speedOfLight;
}
public double getEps0() {
return eps0;
}
public double getMu0() {
return mu0;
}
public double getTimeStep() {
return timeStep;
}
public Detector getCollisionDetector() {
return collisionDetector;
}
public CollisionAlgorithm getCollisionAlgorithm() {
return collisionResolver;
}
public FieldSolver getGridSolver() {
/*
* For the distributed tests to pass we need to create new grid solver so that the two
* simulation instances do not share the cell iterator!
*/
return gridSolver.clone();
}
public PoissonSolver getPoissonSolver() {
return poissonSolver;
}
public Solver getParticleSolver() {
return particleSolver;
}
public String getOCLParticleSolver() {
return this.OCLParticleSolver;
}
public InterpolatorAlgorithm getInterpolator() {
return interpolator;
}
public String getOCLGridInterpolator() {
return this.OCLGridInterpolator;
}
public String getRunid() {
return runid;
}
public List<Diagnostics> getDiagnostics() {
return diagnostics;
}
public int getNumOfNodes() {
return numOfNodes;
}
public GeneralBoundaryType getBoundaryType() {
return boundaryType;
}
public int getIterations() {
return iterations;
}
public String getIplServer() {
return iplServer;
}
public boolean useGrid() {
return useGrid;
}
public String getIplPool() {
return iplPool;
}
//----------------------------------------------------------------------------------------------
// MORE COMPLEX GETTERS / BUILDERS
//----------------------------------------------------------------------------------------------
public double getCellWidth() {
return simulationWidth / gridCellsX;
}
public double getCellHeight() {
return simulationHeight / gridCellsY;
}
/**
* Build the combined force for simulation.
*/
public CombinedForce getForce() {
CombinedForce combinedForce = new CombinedForce();
for (Force f : forces) {
combinedForce.add(f);
}
return combinedForce;
}
private List<ParticleFactory> defaultParticleFactories() {
// Random seed
long seed = (long) Math.random();
// If asList() is used the resulting list will have a fixed size!
List<ParticleFactory> particleFactories = Arrays.asList(
new ParticleFactory(numOfParticles / 2, 1, 1, particleRadius,
PositionDistribution.RANDOM, VelocityDistribution.RANDOM,
particleMaxSpeed / 10, particleMaxSpeed / 10, particleMaxSpeed,
false, seed, seed),
new ParticleFactory(numOfParticles / 2, 1, -1, particleRadius,
PositionDistribution.RANDOM, VelocityDistribution.RANDOM,
particleMaxSpeed / 10, particleMaxSpeed / 10, particleMaxSpeed,
false, seed, seed));
return particleFactories;
}
/**
* If no particles are specified creates random particles.
*
* !!! IMPORTANT !!! Always returns deep copy of the actual particle list!
*/
public List<Particle> getParticles() {
if (particles.size() == 0) {
this.particles = (new ParticleLoader()).load(defaultParticleFactories(),
simulationWidth, simulationHeight, gridCellsX, gridCellsY);
}
return cloneParticles();
}
private List<Particle> cloneParticles() {
List<Particle> copy = new ArrayList<Particle>();
for (Particle p : particles) {
copy.add(p.copy());
}
return copy;
}
public GridBoundaryType getGridBoundary() {
switch (boundaryType) {
case Periodic:
return GridBoundaryType.Periodic;
case Hardwall:
return GridBoundaryType.Hardwall;
default:
return GridBoundaryType.Hardwall;
}
}
public ParticleBoundaryType getParticleBoundary() {
switch (boundaryType) {
case Periodic:
return ParticleBoundaryType.Periodic;
case Hardwall:
return ParticleBoundaryType.Hardwall;
default:
return ParticleBoundaryType.Hardwall;
}
}
public ParticleIterator getParticleIterator() {
if (numOfThreads == 1) {
return new SequentialParticleIterator();
} else if (numOfThreads > 1) {
return new ParallelParticleIterator(numOfThreads, getThreadsExecutor());
} else {
throw new RuntimeException("Invalid number of threads: " + numOfThreads);
}
}
public CellIterator getCellIterator() {
if (numOfThreads == 1) {
return new SequentialCellIterator();
} else if (numOfThreads > 1) {
return new ParallelCellIterator(numOfThreads, getThreadsExecutor());
} else {
throw new RuntimeException("Invalid number of threads: " + numOfThreads);
}
}
/**
* Create threads executor on the fly according to demand.
*/
private ExecutorService getThreadsExecutor() {
if (threadsExecutor == null) {
threadsExecutor = Executors.newFixedThreadPool(numOfThreads);
}
return threadsExecutor;
}
//----------------------------------------------------------------------------------------------
// SETTERS (Overwrite default values programatically)
//----------------------------------------------------------------------------------------------
public void setSimulationType(int simulationType) {
this.simulationType = simulationType;
}
public void setWriteToFile(int writeTo) {
this.writeToFile = writeTo;
}
/**
* @deprecated Use setGridStep() and setGridCellsX() instead.
*/
@Deprecated
public void setSimulationWidth(double simulationWidth) {
this.simulationWidth = simulationWidth;
}
/**
* @deprecated Use setGridStep() and setGridCellsY() instead.
*/
@Deprecated
public void setSimulationHeight(double simulationHeight) {
this.simulationHeight = simulationHeight;
}
public void setGridCellsX(int gridCellsX) {
this.gridCellsX = gridCellsX;
this.simulationWidth = this.gridStep*gridCellsX;
}
public void setGridCellsY(int gridCellsY) {
this.gridCellsY = gridCellsY;
this.simulationHeight = this.gridStep*gridCellsY;
}
public void setSpeedOfLight(double speedOfLight) {
if( (this.eps0 * this.mu0) == speedOfLight*speedOfLight ) {
this.speedOfLight = speedOfLight;
} else {
System.out.println("Your chosen speed of light is in contradiction to the values of eps_0 and mu_0 !! Default value of c is used instead!!");
}
}
public void setTimeStep(double timeStep) {
this.timeStep = timeStep;
this.iterations = (int) Math.ceil(tMax/timeStep);
}
public void setTMax(double TMax) {
this.tMax = TMax;
this.iterations = (int) Math.ceil(TMax/timeStep);
}
public void setGridStep(double gridstep) {
this.gridStep = gridstep;
}
public void setSpectrumStep(int spectrumstep) {
this.spectrumStep = spectrumstep;
}
public void setFilePath(String filepath) {
this.filePath = filepath;
}
public void setRelativistic(boolean rel) {
this.relativistic = rel;
}
public void setCollisionDetector(Detector collisionDetector) {
this.collisionDetector = collisionDetector;
}
public void setCollisionResolver(CollisionAlgorithm collisionResolver) {
this.collisionResolver = collisionResolver;
}
public void setGridSolver(FieldSolver gridSolver) {
this.gridSolver = gridSolver;
}
public void setPoissonSolver(PoissonSolver poissonSolver) {
this.poissonSolver = poissonSolver;
}
public void setParticleSolver(Solver particleSolver) {
this.particleSolver = particleSolver;
}
public void setOCLParticleSolver(String OCLParticleSolver) {
this.OCLParticleSolver = OCLParticleSolver;
}
public void setInterpolator(InterpolatorAlgorithm interpolator) {
this.interpolator = interpolator;
}
public void setOCLGridInterpolator(String OCLGridInterpolator) {
this.OCLGridInterpolator = OCLGridInterpolator;
}
public void setRunid(String runid) {
this.runid = runid;
}
public void setDiagnostics(List<Diagnostics> diagnostics) {
this.diagnostics = diagnostics;
}
public void setForces(List<Force> forces) {
this.forces = forces;
}
public void addForce(Force force) {
this.forces.add(force);
}
public void setNumOfParticles(int numOfParticles) {
this.numOfParticles = numOfParticles;
}
public void setParticleList(List<Particle> particles) {
this.numOfParticles = particles.size();
this.particles = particles;
}
public void setParticleRadius(double particleRadius) {
this.particleRadius = particleRadius;
}
public void setParticleMaxSpeed(double particleMaxSpeed) {
this.particleMaxSpeed = particleMaxSpeed;
}
public void addParticle(Particle p) {
particles.add(p);
}
/**
* @deprecated Use setTimeStep() and setTMax() instead.
*/
@Deprecated
public void setIterations(int iterations) {
this.iterations = iterations;
}
public void setNumOfNodes(int numOfNodes) {
this.numOfNodes = numOfNodes;
}
public void setBoundary(GeneralBoundaryType boundaryType) {
this.boundaryType = boundaryType;
}
public void setIplServer(String iplServer) {
this.iplServer = iplServer;
}
public void useGrid(boolean useGrid) {
this.useGrid = useGrid;
}
public void setIplPool(String iplPool) {
this.iplPool = iplPool;
}
public void setNumOfThreads(int numOfThreads) {
this.numOfThreads = numOfThreads;
}
//----------------------------------------------------------------------------------------------
// VARIOUS
//----------------------------------------------------------------------------------------------
public Settings() {
}
/**
* Overwrites default values with file input.
*/
public Settings(String fileName) {
this();
// Parse file
throw new UnsupportedOperationException();
}
/**
* Overwrites default values with command line input.
*/
public Settings(String[] cmdLine) {
throw new UnsupportedOperationException();
}
/**
* Has to be called every time numOfThreads is set to a value higher than 1!
* Terminates the threads used by executor service. Is idempotent (can be
* called multiple times without side-effects).
*/
public void terminateThreads() {
if (threadsExecutor != null) {
threadsExecutor.shutdown();
threadsExecutor = null;
}
}
}