Advertisement
Guest User

Untitled

a guest
Sep 23rd, 2019
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 9.08 KB | None | 0 0
  1. package ar.edu.itba.ss.tpe4;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.HashMap;
  5. import java.util.List;
  6. import java.util.stream.Collectors;
  7. import java.awt.geom.Point2D;
  8.  
  9. public class LennardJonesGasManager {
  10.    
  11.     private final Grid grid;
  12.     private double balanceTime;
  13.     private HashMap<Particle, Double> positionMap;
  14.  
  15.     public LennardJonesGasManager(Grid grid) {
  16.         this.grid = grid;
  17.         this.balanceTime = 0.0;
  18.         this.positionMap = new HashMap<>();
  19.  
  20.         for (Particle particle: grid.getParticles()) {
  21.             this.positionMap.put(particle, particle.getPosition().x);
  22.         }
  23.     }
  24.  
  25.     private double getParticleForce(double distance) {
  26.         // Formula to get the force applied from one particle to another, extracted from the slides
  27.         double coefficient = Configuration.GAS_L * Configuration.GAS_EPSILON / Configuration.GAS_Rm;
  28.         double repulsion = Math.pow((Configuration.GAS_Rm / distance), Configuration.GAS_L + 1);
  29.         double attraction =Math.pow((Configuration.GAS_Rm / distance), Configuration.GAS_J + 1);
  30.         return - coefficient * (repulsion - attraction);
  31.     }
  32.  
  33.     private Boolean isBalanced() {
  34.         // returns true only if there are the same amount of particles in both chambers
  35.         List<Particle> particles = grid.getParticles();
  36.  
  37.         Integer initialChamberAmount = 0;
  38.         for (Particle particle: particles) {
  39.             if (isInFirstChamber(particle)) {
  40.                 initialChamberAmount += 1;
  41.             }
  42.         }
  43.  
  44.         return Math.floor(initialChamberAmount - particles.size() / 2) == 0;
  45.     }
  46.  
  47.     private double getTimeLimit() {
  48.         // We have to handle different break conditions to allow for balance time exercises
  49.         double timeLimit = Integer.MAX_VALUE;
  50.        
  51.         switch(Configuration.getTimeLimit()) {
  52.             case -1:
  53.                 timeLimit = this.balanceTime > 0 ? this.balanceTime : Integer.MAX_VALUE;
  54.                 break;
  55.             case -2:
  56.                 timeLimit = this.balanceTime > 0 ? this.balanceTime * 2 : Integer.MAX_VALUE;
  57.             default:
  58.                 timeLimit = Configuration.getTimeLimit();
  59.         }
  60.  
  61.         return timeLimit;
  62.     }
  63.  
  64.     public Boolean isInFirstChamber(Particle particle) {
  65.         return particle.getPosition().x < Configuration.GAS_BOX_SPLIT;
  66.     }
  67.  
  68.     public void updatePositionByBouncing(List<Particle> particles) {
  69.         // The particle has to bounce between the different walls
  70.         for (Particle particle: particles) {
  71.             Boolean isOutsideTopBound = particle.getPosition().y >= Configuration.GAS_BOX_HEIGHT;
  72.             Boolean isOutsideBottomBound = particle.getPosition().y <= 0;
  73.             Boolean isOutsideRightBound = particle.getPosition().x >= Configuration.GAS_BOX_WIDTH;
  74.             Boolean isOutsideLeftBound = particle.getPosition().x <= 0;
  75.             Boolean isWithinHole = particle.getPosition().y >= Configuration.GAS_BOX_HOLE_POSITION && particle.getPosition().y <= Configuration.GAS_BOX_HOLE_POSITION + Configuration.GAS_BOX_HOLE_SIZE;
  76.  
  77.             if (isOutsideTopBound || isOutsideBottomBound) {
  78.                 particle.setVelocity(particle.getVelocity().x, -particle.getVelocity().y);
  79.             }
  80.  
  81.             if (isOutsideLeftBound || isOutsideRightBound) {
  82.                 particle.setVelocity(-particle.getVelocity().x, particle.getVelocity().y);
  83.             }
  84.  
  85.             // If the particle is in the area that's affected by the split
  86.             if (!isWithinHole) {
  87.                 double lastX = this.positionMap.get(particle);
  88.                 Boolean changedChamber = !isInFirstChamber(particle) && lastX < Configuration.GAS_BOX_SPLIT || isInFirstChamber(particle) && lastX > Configuration.GAS_BOX_SPLIT;
  89.                 // Only make it bounce if it CHANGED the chamber, but don't update the position in the position map
  90.                 // so we don't enter an endless loop.
  91.                 if (changedChamber) {
  92.                     particle.setVelocity(-particle.getVelocity().x, particle.getVelocity().y);
  93.                     continue;
  94.                 }
  95.             }
  96.  
  97.             this.positionMap.put(particle, particle.getPosition().x);
  98.         }
  99.     }
  100.  
  101.     public double distance(Particle a, Particle b) {
  102.         // Calculate euclidean distance between a particle a and a particle b in 2D.
  103.         return Math.sqrt(Math.pow(b.getPosition().x - a.getPosition().x, 2) + Math.pow(b.getPosition().y - a.getPosition().y, 2));
  104.     }
  105.  
  106.     public List<Particle> getClosestParticles(Particle particle) {
  107.         List<Particle> particles = grid.getParticles();
  108.         // TODO: use cellindex method
  109.         // Get particles closer to the constant GAS_RANGE and larger than 0 (to avoid taking myself into account)
  110.         // And only those that are in the same chamber
  111.         return particles.stream().filter(p -> distance(particle, p) > 0 && distance(particle, p) <= Configuration.GAS_RANGE && isInFirstChamber(particle) == isInFirstChamber(p)).collect(Collectors.toList());
  112.     }
  113.  
  114.     private Point2D.Double getAppliedForce (Particle particle) {
  115.         // First we get the particles that affect our motion (closer to GAS_RANGE distance)
  116.         List<Particle> closeParticles = getClosestParticles(particle);
  117.         double totalForceX = 0.0;
  118.         double totalForceY = 0.0;
  119.  
  120.         // Then, we iterate over the closest particles, calculate the modulus of the force
  121.         // then calculate the angle of the force (by using the position beteween the two particles)
  122.         // then with that angle we calculate the components of the force in X and Y coordinates
  123.         // and then we add that to the total force (for each component)
  124.         for (Particle p: closeParticles) {
  125.             double forceModulus = getParticleForce(distance(p, particle));
  126.             double forceAngle = Math.atan2(p.getPosition().y - particle.getPosition().y, p.getPosition().x - particle.getPosition().x);
  127.             totalForceX += Math.cos(forceAngle) * forceModulus;
  128.             totalForceY += Math.sin(forceAngle) * forceModulus;
  129.         }
  130.  
  131.         return new Point2D.Double(totalForceX, totalForceY);
  132.     }
  133.  
  134.     private Point2D.Double getAppliedAcceleration (Particle particle) {
  135.         // Divide each component of the force by the mass, and return that vector.
  136.         Point2D.Double force = getAppliedForce(particle);
  137.         return new Point2D.Double(force.x / particle.getMass(), force.y / particle.getMass());
  138.     }
  139.  
  140.     public void verletUpdate(List<Particle> previousParticles) {
  141.         // This is almost a true copy from the collider,
  142.         // except we calculate a new position and a new velocity
  143.         // for both X and Y coordinates
  144.         List<Particle> currentParticles = grid.getParticles();
  145.        
  146.         for(int i = 0; i < currentParticles.size(); i++) {
  147.             Particle currParticle = currentParticles.get(i);
  148.             Particle prevParticle = previousParticles.get(i);
  149.             Point2D.Double acceleration  = getAppliedAcceleration(currParticle);
  150.             double newPositionX = 2 * currParticle.getPosition().getX() - prevParticle.getPosition().getX()
  151.                     + Math.pow(Configuration.getTimeStep(), 2) * acceleration.x; //+error
  152.             double newPositionY = 2 * currParticle.getPosition().getY() - prevParticle.getPosition().getY()
  153.                     + Math.pow(Configuration.getTimeStep(), 2) * acceleration.y; //+error
  154.             double newVelocityX = (newPositionX - prevParticle.getPosition().getX()) / (2 * Configuration.getTimeStep()); // + error
  155.             double newVelocityY = (newPositionY - prevParticle.getPosition().getY()) / (2 * Configuration.getTimeStep()); // + error
  156.            
  157.             prevParticle.setPosition(currParticle.getPosition().getX(), currParticle.getPosition().getY());
  158.             prevParticle.setVelocity(currParticle.getVelocity().getX(), currParticle.getPosition().getY());
  159.             currParticle.setPosition(newPositionX, newPositionY);
  160.             currParticle.setVelocity(newVelocityX, newVelocityY);
  161.         }
  162.     }
  163.  
  164.     // Euler Algorithm evaluated in (- timeStep)
  165.     private List<Particle> initPreviousParticles(List<Particle> currentParticles) {
  166.         // This is almost a true copy from the collider,
  167.         // except we calculate a previous position and a previous velocity
  168.         // for both X and Y coordinates
  169.         List<Particle> previousParticles = new ArrayList<>();
  170.         for(Particle p : currentParticles) {
  171.             Particle prevParticle = p.clone();
  172.             Point2D.Double force = getAppliedForce(p);
  173.             double prevPositionX = p.getPosition().getX() - Configuration.getTimeStep() * p.getVelocity().getX()
  174.                     + Math.pow(Configuration.getTimeStep(), 2) * force.x / (2 * p.getMass()); // + error
  175.             double prevPositionY = p.getPosition().getY() - Configuration.getTimeStep() * p.getVelocity().getY()
  176.                     + Math.pow(Configuration.getTimeStep(), 2) * force.y / (2 * p.getMass()); // + error
  177.             double prevVelocityX = p.getVelocity().getX() - (Configuration.getTimeStep() / p.getMass()) * force.x;// + error
  178.             double prevVelocityY = p.getVelocity().getX() - (Configuration.getTimeStep() / p.getMass()) * force.y;// + error
  179.             prevParticle.setPosition(prevPositionX, prevPositionY);
  180.             prevParticle.setVelocity(prevVelocityX, prevVelocityY);
  181.             previousParticles.add(prevParticle);
  182.         }
  183.        
  184.         return previousParticles;
  185.     }
  186.  
  187.     public void execute() {
  188.         double accumulatedTime = 0.0;
  189.         List<Particle> previousParticles = initPreviousParticles(grid.getParticles());
  190.  
  191.         if (Configuration.getTimeLimit() == -1)
  192.         while(Double.compare(accumulatedTime, getTimeLimit()) <= 0) {
  193.             Configuration.writeGasOvitoOutputFile(accumulatedTime, grid.getParticles());
  194.  
  195.             // get balance time
  196.             if (balanceTime == 0 && isBalanced()) {
  197.                 balanceTime = accumulatedTime;
  198.             }
  199.  
  200.             // update position if the particles bounce
  201.             updatePositionByBouncing(grid.getParticles());
  202.  
  203.             // increase time by dt
  204.             accumulatedTime += Configuration.getTimeStep();
  205.  
  206.             // update position and velocity
  207.             verletUpdate(previousParticles);
  208.         }
  209.     }
  210.  
  211. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement