/* * Compton.java * Simple Animated Simulation of Compton Scattering * Code: Jan Humble * * */ import java.applet.*; import java.awt.*; public class Compton extends Applet implements Runnable{ public static double PLANCK = 4.14; // 10 ^ -18 eVs public static double COMPTONWAVELENGTH = 0.02426; // Å public static double LIGHTSPEED = 2.998; // 10 ^ 8 m/s int dY, dX; // Applet size parameters Thread animThread; // Thread animation process Image offscreen; // Background graphics buffer Font font1 = new Font("Helvetica", Font.BOLD, 14); Font font2 = new Font("Helvetica", Font.PLAIN, 10); Font font3 = new Font("Helvetica", Font.BOLD, 12); // private Button emit_button; int time = 0; double deltaT = 50; double theta, phi; // Compton particles Photon photon; Electron electron; public void init(){ // Get the drawing area of the applet dY=size().height; dX=size().width; // Button /*emit_button = new Button("Emit"); emit_button.setBackground(Color.white); this.add(emit_button); emit_button.locate(200, 200); */ double photonenergy = (Double.valueOf(getParameter("photonenergy"))).doubleValue(); photon = new Photon(photonenergy, 30, dY/2); electron = new Electron(0.0, dX/2, dY/2); theta = phi = 0.0; } public void start() { if (animThread == null){ animThread = new Thread(this); animThread.start(); } } public void stop() { animThread = null; } public void run() { while (animThread != null) { while (time < 100) { // Use sleep to pause between movements try { Thread.sleep((int)(50)); } catch (InterruptedException e) {} // Collision detection if (photon.currentX == electron.currentX && photon.currentY == electron.currentY) { collision(photon, electron); } photon.move(deltaT); electron.move(deltaT); repaint(); time++; } // Reset the process time = 0; electron.reset(); photon.reset(); theta = phi = 0.0; } } public void update (Graphics g){ // Update using double buffering Dimension d = this.size(); if (offscreen == null) offscreen = this.createImage(d.width, d.height); // Draw to background buffer g = offscreen.getGraphics(); paint(g); // draw from background buffer to screen buffer g = this.getGraphics(); g.drawImage(offscreen, 0, 0, this); } /* collision: */ /* Calculates new parameters after Compton Collision. */ /* Can be overloaded to simulate collisions with */ /* different kinds of particles. */ public void collision(Photon photon, Electron electron) { double prefreq = photon.frequency; double prewave = photon.wavelength; double postfreq, postwave; // Calculate a random theta angle theta = Math.random() * Math.PI; // 0 < theta < 180 // theta = Math.PI; postwave = Math.abs (prewave + COMPTONWAVELENGTH * (1 - Math.cos(theta))); postfreq = LIGHTSPEED / postwave; // Calculate the corresponding Compton scat. angle phi = Math.atan ( postfreq * Math.sin(theta) / (prefreq - postfreq * Math.cos(theta))); // set new direction and velocities for the particles electron.setPath(phi, photon.vel); photon.setPath(-theta, photon.vel); // set new particle values electron.energy = Compton.PLANCK * (prefreq - postfreq); photon.wavelength = postwave; photon.frequency = postfreq; photon.energy = postfreq * Compton.PLANCK; photon.tailLength = (int) (photon.tailLength * postwave / prewave); } public String num2string (double num) { String s =Double.toString(num); return s.substring(0, Math.min(6, s.length())); } public void frameInfo(Graphics g) { // Draw label g.setColor(Color.black); g.setFont(font1); g.drawString("Compton Effect", 8, 20); g.setFont(font2); g.drawString("time = " + Integer.toString(time), 20, 40); // draw axis with origin on the electron g.setColor(Color.lightGray); g.drawLine(0, (int) electron.startY, dX, (int) electron.startY); g.drawLine((int) electron.startX, 0, (int) electron.startX, dY); // Draw photon info g.setColor(Color.blue); g.setFont(font3); g.drawString("Photon", 20, dY - 60); g.setFont(font2); g.drawString("Energy = " + num2string(photon.energy) + " keV", 20, dY-48); g.drawString("freq = " + num2string(photon.frequency) + " EHz", 20, dY-36); g.drawString("wavelength = " + num2string(photon.wavelength) + " Å", 20, dY-24); g.drawString("theta = " + num2string(theta * 180/Math.PI), 20, dY-12); // Draw electron info g.setColor(Color.red); g.setFont(font3); g.drawString("Electron", dX - 140, dY - 60); g.setFont(font2); g.drawString("Kin. energy = " + num2string(electron.energy) + " keV", dX - 140, dY-42); g.drawString("phi = " + num2string(electron.angle * 180/Math.PI), dX - 140, dY-30); } public void paint(Graphics g) { // Clear screen g.setColor(Color.white); g.fillRect(0, 0, dX, dY); // Draw particles photon.draw(g); electron.draw(g); frameInfo(g); } } /* ------------------------------------------------ */ /* Base Particle class */ /* */ /* ------------------------------------------------ */ abstract class Particle { Color color; double startX, startY; double currentX, currentY; double startVel, vel, velX, velY; double startAngle, angle; double energy, startenergy; Particle(double energy, int startX, int startY, double startAngle, double startVel, Color color) { this.startX = startX; this.startY = startY; this.currentX = startX; this.currentY = startY; this.startAngle = startAngle; this.startVel = startVel; this.color = color; this.energy = this.startenergy = energy; setPath(startAngle, startVel); } public void reset() { currentX = startX; currentY = startY; energy = startenergy; setPath(startAngle, startVel); } public void setPath(double newAngle, double vel) { this.angle = newAngle; this.vel = vel; velX = vel*Math.cos(angle); velY = vel*Math.sin(angle); } public void move(double deltaT) { currentX = currentX + velX*deltaT; currentY = currentY - velY*deltaT; } abstract void draw(Graphics g); } /* ------------------------------------------------ */ /* Electron class: Inherits Particle */ /* */ /* ------------------------------------------------ */ class Electron extends Particle{ final double restenergy = 511; // keV int drawDiameter; // define diameter to draw on screen // Constructor Electron(double energy, int startX, int startY) { super(energy, startX, startY, 0, 0, Color.red); this.drawDiameter = 15; } public void draw(Graphics g) { g.setColor(color); g.fillOval((int) currentX - drawDiameter/2, (int) currentY - drawDiameter/2, drawDiameter, drawDiameter); } } /* ------------------------------------------------ */ /* Photon class: Inherits Particle */ /* */ /* ------------------------------------------------ */ class Photon extends Particle { double frequency, wavelength; final int TAIL = 60; int drawAmplitud, tailLength; // photon graphical parameters // Constructor Photon (double energy, int startX, int startY) { super(energy, startX, startY, 0.0, 0.1, Color.blue); this.frequency = energy / Compton.PLANCK; this.wavelength = Compton.LIGHTSPEED / frequency; this.drawAmplitud = 5; this.tailLength = TAIL; } public void reset() { super.reset(); this.frequency = energy / Compton.PLANCK; this.wavelength = Compton.LIGHTSPEED / frequency; this.tailLength = TAIL; } public void draw(Graphics g) { g.setColor(color); double x1, x2, y1, y2, x1r, x2r, y1r, y2r; for (int x = - tailLength; x < 0; x++) { // Calculate animated sinus tail y1 = Math.sin((currentX + x)*8*Math.PI/tailLength) * drawAmplitud; y2 = Math.sin((currentX + x+1)*8*Math.PI/tailLength) * drawAmplitud; // Rotate tail according to photon path angle x1r = currentX + Math.cos(angle)*x - Math.sin(-angle)*y1; y1r = Math.sin(-angle)*x + Math.cos(angle)*y1 + currentY; x2r = currentX + Math.cos(angle)*(x+1) - Math.sin(-angle)*y2; y2r = Math.sin(-angle)*(x+1) + Math.cos(angle)*y2 + currentY; g.drawLine((int) x1r, (int) y1r, (int) x2r, (int) y2r); // g.fillOval(currentX - 5, currentY - 5, 10, 10); } } }