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; } } }