Site hosted by Angelfire.com: Build your free website today!
/******************************************************************

        Java Applet fmr1.java
        April 1997 - Michael J. Hurben

This applet provides a simulation of a simple FMR experiment.
The user can choose between field swept and frequency swept models.
The applet has two parts.  On the left side, the H field, microwave
pump field, and magnetization vectors are drawn in motion. On the
right side, a plot of the absorbed microwave power versus field
or frequency is drawn in 'real' time.

All quantities are in arbitrary units, and values have been
chosen in order to provide the most visually pleasing display.
Later versions of this applet will be more physically rigorous.
For now, the applet aims to provide a simple qualitative
understanding of a typical FMR experiment.

The applet uses double buffering in an attempt to
eliminate (or reduce) the flicker in the animation.  

******************************************************************/

import java.applet.Applet;
import java.awt.*;

public class fmr1 extends Applet implements Runnable
  {
    Dimension offDimension, d;  // Variables used to create an
    Image offImage;             // offscreen image via the update() 
    Graphics offGraphics;       // method, to reduce flicker

    int vDx = 5;            //
    int vDy = 5;            //  Defines the drawing area
    int vDheight = 190;     //  for the vectors (left hand side)
    int vDwidth = 150;      //

    int gDx = 2*vDx+vDwidth+50;     //
    int gDy = vDy;                  //  Defines drawing area for
    int gDheight = vDheight-20;     //  the graph (right hand side)
    int gDwidth = 200;              //

    int bx = vDx+vDwidth/2;     //   Coordinates for vector bases
    int by = vDheight-30;       //   (centered)

    int tipWidth =10;         //  Size of the vector
    int tipLength = 16;       //  arrow head

    int Hfield = 0;           // Initial value for Hfield

    int Mbasex=bx;            // Set all initial variables    
    int Mbasey=by;            // for the magnetization,
    int Mtipx=bx;             // or M, vector
    int Mtipy=by-vDwidth/2-6;
    int Mlength=vDwidth/2-6;
    int[] MtipPx={Mtipx, Mtipx+tipWidth/2, Mtipx-tipWidth/2};
    int[] MtipPy={Mtipy, Mtipy+tipLength, Mtipy+tipLength};

    int Hbasex=bx;            // Set all initial variables   
    int Hbasey=by;            // for the static field,
    int Htipx=bx;             // or H, vector
    int Htipy=by-vDwidth/2-6;
    int Hlength=vDwidth/2-6;
    int[] HtipPx={Htipx, Htipx+tipWidth/2, Htipx-tipWidth/2};
    int[] HtipPy={Htipy-Hfield, Htipy-Hfield+tipLength,
     Htipy-Hfield+tipLength};

    int hbasex=bx;             // Set all inital variables    
    int hbasey=6*gDy;          // for the microwave pump,
    int htipx=bx+60;           // or h, vector
    int htipy=6*gDy;
    int hlength=60;
    int[] htipPx={htipx, htipx-tipLength, htipx-tipLength};
    int htipPy[]={htipy, htipy+tipWidth/2, htipy-tipWidth/2};

    int tip1x = Mtipx;        //
    int tip1y = Mtipy;        // Temp variables used to draw arrow
    int tip2x = Mtipx;        // on magnetization vector
    int tip2y = Mtipy;        //

    int tmax = 40000;         // Maximum time
    int time = 0;             // Starting time
           
    int Hfield2 = Hfield;     // Field H at time+1 : initial value
    int Hmax = 30;            // Range for sweeping
    int Hmin = -30;           // the H field strength

    int x1, x2, y1, y2;       // Used in drawLine() to create plot
    
    double center = (2*3.14/4000);   // Center frequency, arb units
    double c = center;               // Resonance frequency
    double c2 = c;                   // Res freq at time+1
    double freq = center;            // Current frequency at given time
    double freq2 = center;           // Frequency at time+1
    double pow = 1;                  // Power 
    double amp = 1;                  // Amplitude = sqrt(power)
    double pow1=1, pow2=1;           // Power at time and time+1

    double damp = 1;            // Initial damping constant

    boolean freqSweep = true;   // For selecting freq or field sweep          
    boolean oldScreen = true;   // For redrawing plot  

    Thread t;                   
    Button b1, b2, b3, b4, b5, b6;
    Checkbox cb1, cb2;

    public void init()                      //  Initialize :
      {                                     //  Set up the user interface
        setLayout(new BorderLayout(10,10)); //  and start the thread.
        Panel p1 = new Panel();             //
        p1.setLayout(new GridLayout(8,1));

        CheckboxGroup cbg = new CheckboxGroup();   // Radio buttons

        cb1 = new Checkbox("Sweep Frequency", cbg, true);
        cb2 = new Checkbox("Sweep Field", cbg, false);

        b1 = new Button("Start New Plot");
        b2 = new Button("More Damping");
        b3 = new Button("Less Damping");
        b4 = new Button("Pause");
        b5 = new Button("Resume");
        b6 = new Button("Finish");

        p1.add(cb1);
        p1.add(cb2);
        p1.add(b1);
        p1.add(b2);
        p1.add(b3);
        p1.add(b4);
        p1.add(b5);
        p1.add(b6);
        add("East", p1);       // Put buttons on the far right side

        t = new Thread(this);
        t.start();      
      }

    public boolean action(Event e, Object o)
      {
        if (e.target.equals(cb1))     //  Respond to button pushes
          {                           //  or checkbox selections
            t.suspend();
            freqSweep = true;
            time=0;
            oldScreen = false;
            t.resume();
          }
        else if (e.target.equals(cb2))
          {
            t.suspend();
            freqSweep = false;
            time=0;
            oldScreen = false;
            t.resume();
          }
        else if (o.equals("More Damping"))
          {
            damp = damp*1.1;
            time = 0;
            oldScreen = false;
          }
        else if (o.equals("Less Damping"))
          {
            damp = damp*0.9;
            time = 0;
            oldScreen = false;
          }
        else if (o.equals("Pause"))
          {
            t.suspend();
          }
        else if (o.equals("Resume"))
          {
            t.resume();
          }
        else if (o.equals("Finish"))
          { 
            t.stop();
          }
        else if (o.equals("Start New Plot"))
          {
            t.suspend();
            time=0;
            t.resume();
            oldScreen=false;    
          }
        return true;
      }

    public void run()      
      {                      
        while(true)        
          {
            if(freqSweep)
              {
                freq = center/2+center*time/tmax;
                freq2 = freq+center/tmax;
                Hfield = 0;
                Hfield2 = 0;
                c = center;
                c2 = c;
              }
            else
              {
                freq = center;
                freq2 = freq;
                Hfield = (int) (Hmin+(Hmax-Hmin)*time/tmax);
                Hfield2 = (int) (Hmin+(Hmax-Hmin)*(time+1)/tmax);
                c = center/2+center*time/tmax;
                c2 = c+center/tmax;
              }

            HtipPy[0] = Mbasey-Mlength-Hfield;              
            HtipPy[1] = Mbasey-Mlength-Hfield+tipLength;    
            HtipPy[2] = Mbasey-Mlength-Hfield+tipLength;   

            double nfreq = (c-freq)*(c-freq)*4e7;
            double nfreq2 = (c2-freq2)*(c2-freq2)*4e7;

            pow = damp*damp/(nfreq+damp*damp);
            pow1 = pow;
            pow2 = damp*damp/(nfreq2+damp*damp);            

            x1=(int) (gDx+gDwidth*time/tmax);
            x2=(int) (gDx+gDwidth*(time+1)/tmax);

            y1=(int) (gDy+gDheight-(gDheight-5)*pow1);
            y2=(int) (gDy+gDheight-(gDheight-5)*pow2);

            amp = Math.sqrt(pow);

            int a = (int) (Mlength*amp*0.707*
             (Math.cos(time*freq)));
            int b = (int) (Mlength*0.5*amp*0.707*
             (Math.sin(time*freq)));
            int pump = (int) (hlength*Math.cos(time*freq));
            htipx = hbasex+pump;
            Mtipx = Mbasex+a;
            Mtipy = (int) (Mbasey-Mlength*Math.sqrt(1-amp*amp/2)-b);

           //  Now calculate the vertices for the triangular vector tip

            double denom = Math.sqrt((Mtipy-Mbasey)*(Mtipy-Mbasey)
             +(Mtipx-Mbasex)*(Mtipx-Mbasex));
            tip1x=Mtipx+(int)(((Mbasex-Mtipx)*tipLength+(tipWidth/2)
             *(Mtipy-Mbasey))/denom);
            tip2x=Mtipx+(int)(((Mbasex-Mtipx)*tipLength-(tipWidth/2)
             *(Mtipy-Mbasey))/denom);
            tip1y=Mtipy+(int)(((Mbasey-Mtipy)*tipLength-(tipWidth/2)
             *(Mtipx-Mbasex))/denom);
            tip2y=Mtipy+(int)(((Mbasey-Mtipy)*tipLength+(tipWidth/2)
             *(Mtipx-Mbasex))/denom);

            MtipPx[0] = Mtipx;
            MtipPx[1] = tip1x;
            MtipPx[2] = tip2x;
            MtipPy[0] = Mtipy;
            MtipPy[1] = tip1y;
            MtipPy[2] = tip2y;

            htipPx[0] = htipx;
            if(htipx >= Mbasex)
              {
                htipPx[1] = htipx-tipLength;
                htipPx[2] = htipx-tipLength;
              }
            else
              {
                htipPx[1] = htipx+tipLength;
                htipPx[2] = htipx+tipLength;
              }

            htipPy[0] = htipy;
            htipPy[1] = htipy+tipWidth/2;
            htipPy[2] = htipy-tipWidth/2;

            if (time < tmax)

              {
                repaint();      
                time=time+1;    
              }
            else
              {
                t.suspend();
              }
          }
      }
                                          //
   public void paint(Graphics g)          //  The guts of the painting
     {                                    //  is done in the update()
        d=size();                         //  method
        update(g);                        //
     }

   public void update(Graphics g)
     {                                        //
       if((offGraphics ==null)                // Setup an off-screen image
        ||(d.width !=offDimension.width)      // via the update() method.
        || (d.height != offDimension.height)) //
          {
             offDimension=d;

             offImage=createImage(d.width, d.height);
             offGraphics=offImage.getGraphics();

          }

       // If start new plot button is pushed,
       // entire applet is redrawn.  Otherwise,
       // only the vector drawing is redone.

       if(!oldScreen)                               
         {                                             
           offGraphics.setColor(getBackground());        
           offGraphics.fillRect(0,0, d.width, d.height); 
           oldScreen=true;                              
         }                                             
                                                     
       else                                         
         {                                             
           offGraphics.setColor(Color.black);
           offGraphics.fillRect(vDx,vDy, vDwidth, vDheight);
         }

       // Draw the Pump (Microwave) Field

       offGraphics.setColor(Color.cyan);
       offGraphics.drawLine(hbasex, hbasey, htipx, htipy);
       offGraphics.fillPolygon(htipPx, htipPy, 3);
       
       // Draw the Magnetic Field Vector

       offGraphics.setColor(Color.blue);
       offGraphics.drawLine(Hbasex, Hbasey, Hbasex,
        (Hbasey-Hlength-Hfield));
       offGraphics.fillPolygon(HtipPx, HtipPy, 3);

       // Draw the Magnetization vector

       offGraphics.setColor(Color.red);
       offGraphics.drawLine(Mbasex, Mbasey, Mtipx, Mtipy);
       offGraphics.fillPolygon(MtipPx, MtipPy, 3);


       // Make sure the M vector actually goes in front & behind!

       if(Mtipx > Mbasex-10-tipWidth/2 && Mtipx < Mbasex+10+tipWidth/2

        && Mtipy < (int) (Mbasey-Mlength*Math.sqrt(1-
        amp*amp/2)))
         {
           offGraphics.setColor(Color.blue);
           offGraphics.drawLine(Hbasex, Hbasey, Hbasex,
            (Hbasey-Hlength-Hfield));
           offGraphics.fillPolygon(HtipPx, HtipPy, 3);
         }        

        // Draw the plot

       offGraphics.setColor(Color.black);
       offGraphics.drawRect(gDx, gDy, gDwidth, gDheight);

       if(freqSweep)
         {
           offGraphics.drawString("Frequency",
            gDx+Mbasex-10, gDy+gDheight+18);
         }
       else
         {
           offGraphics.drawString("Field",
            gDx+Mbasex+5, gDy+gDheight+18);
         }
       offGraphics.drawString("Power", gDx-40, gDy+(gDheight)/2);
       offGraphics.drawLine(x1,y1,x2,y2);          
       g.drawImage(offImage, 0, 0, this);
     }
  }