package ppmrmn;

import java.awt.*;       import java.applet.*;        import java.awt.event.*;
//30 janv 2004

public class RingXtalJDK118 extends Graph implements Runnable {

  private int     numVars = 3,  //number of parameters to be fitted with simplex
                  nbou    = 1,  //1 + number of pulse duration increment
                  ligne   = 2;  //transition position in the density matrix
  private char    choix = 'C';  //for central transition
  private boolean stopFit = false,
                  showCurve = true;
  private double  coeff = 5,          //for signal normalisation use
                  pop = 2,            //for signal normalisation use
                  dureePremiere = 0,  //inital pulse duration
                  dureePas = 1,       //increment of the pulse duration
                  dureeFin = 1,       //final pulse duration
                  dureePremiere1 = 0,
                  dureePremiere2 = 0,
                  dureePremiere3 = 0,
                  amplitude[] = {0.0},        //FID intensity
                  listExpIntensity[] = {0.0}, //experimental intensity
                  /*matEstimation[][] is the matrix for the initial guess
                  values of fitting parameters*/
                  matEstimation[][] = new double[numVars + 1][numVars];

  //°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
  //      Dimensions 760LX390H of the applet to be introduced in its WEB page
  //°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
  private int     hautLB     = 20,  //label height
                  hautBouton = 30,  //button height
                  hautPanel  = 390; //panel height

  //PanelSpin includes panelSpinLabel, panelSpinData,
  //                   panelSpinData2, panelSpinData3, and panelSpinUnit

  Panel panelSpin =       new Panel();      Panel panelSpinLabel = new Panel();
  Panel panelSpinData =   new Panel();      Panel panelSpinData2 = new Panel();
  Panel panelSpinData3 =  new Panel();      Panel panelSpinUnit =  new Panel();

  //panelTransition includes panelSimulation and scrollPaneSimulation

  Panel panelTransition = new Panel();      Panel panelSimulation = new Panel();
  ScrollPane scrollPaneSimulation = new ScrollPane();

  //PanelFit includes panelFitEstim, panelFitBouton, and panelBlanc

  Panel panelFit =        new Panel();      Panel panelFitEstim =   new Panel();
  Panel panelFitBouton =  new Panel();      Panel panelBlanc =      new Panel();

  Choice choiceSpin =       new Choice();
  Choice choiceSequence =   new Choice();
  Choice choiceTransition = new Choice();
  Choice choiceSimplex =    new Choice();

  Button buttonRun =      new Button("Run");
  Button buttonFit =      new Button("Fit");
  Button buttonGraph =    new Button("DeactivateGraph");
  Button buttonPrevious = new Button("Previous");

  Label labelDate =         new Label("30-01-2004");
  Label labelPulse =        new Label("Pulse");
  Label labelDuree =        new Label("Length (µs)");
  Label labelLine =         new Label("Line");
  Label labelIntensite =    new Label("Intensity");
  Label labelOf =           new Label("of");
  Label labelExperimental = new Label("Experimental");
  Label labelExpIntensite = new Label("Intensity");
  Label labelAdvice =       new Label("Deactivate graph speeds up fitting!!!");

  TextField textFieldOmegaQ =         new TextField("0.0");
  TextField textFieldOmegaRF =        new TextField("50.0");

  TextField textFieldDerniereDuree =  new TextField("10.0");
  TextField textFieldPas =            new TextField("0.5");
  TextField textFieldPremiereDuree =  new TextField("0.0");

  TextField textFieldDerniereDuree2 = new TextField("10.0");
  TextField textFieldPas2 =           new TextField("0.5");
  TextField textFieldPremiereDuree2 = new TextField("0.0");

  TextField textFieldDerniereDuree3 = new TextField("10.0");
  TextField textFieldPas3 =           new TextField("0.5");
  TextField textFieldPremiereDuree3 = new TextField("0.0");

  TextField textFieldOmegaQEst =      new TextField("5");
  TextField textFieldOmegaRFEst =     new TextField("55");

  //100 rows, 7 columns, 2 = SCROLLBARS_NONE
  TextArea textAreaDuree =        new TextArea("", 100, 7,
                                               TextArea.SCROLLBARS_NONE);
  TextArea textAreaIntensite =    new TextArea("", 100, 7,
                                               TextArea.SCROLLBARS_NONE);
  TextArea textAreaExpIntensite = new TextArea(12, 7);  //experimental intensity
  TextArea textAreaParameter =    new TextArea(5, 7);   //fitting parameters

  /**Construct the applet*/
  public RingXtalJDK118() {
  }

  /**Initialize the applet*/
  public void init() {
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

  /**Component initialization*/
  private void jbInit() throws Exception {
    setBackground(Color.white);
    setLayout(null);
    buttonGraph.setBounds(75, 355, 150, hautBouton);
    add(buttonGraph);
    buttonGraph.setVisible(false);
    labelAdvice.setBounds(15, 320, 220, hautBouton);
    add(labelAdvice);
    labelAdvice.setFont(new Font("TimesRoman", Font.PLAIN, 10));
    //necessary for WEB browsers other than IE5.5:
    labelAdvice.setBackground(Color.pink);
    labelAdvice.setVisible(false);

    //panelSpin width + 100
    panelSpin.setBounds(0, 0, 320, hautPanel);
    add(panelSpin);
    panelSpinLabel.setBounds(0, 0, 90, hautPanel-3);
    panelSpin.add(panelSpinLabel);
    panelSpinData.setBounds(90, 0, 60, hautPanel-3);
    panelSpin.add(panelSpinData);
    panelSpinData2.setBounds(150, 0, 60, hautPanel-3);
    panelSpin.add(panelSpinData2);
    panelSpinData3.setBounds(210, 0, 60, hautPanel-3);
    panelSpin.add(panelSpinData3);
    panelSpinUnit.setBounds(270, 0, 50, hautPanel-3);
    panelSpin.add(panelSpinUnit);

    //panelTransition width + 100
    panelTransition.setBounds(320, 0, 220, hautPanel);
    add(panelTransition);

    //panelFit width + 100
    panelFit.setBounds(540, 0, 220, hautPanel);
    add(panelFit);
    panelFit.setVisible(false);

    //****************************  panelSpin  *********************************

    panelSpin.setBackground(Color.pink);
    panelSpin.setLayout(null);
    panelSpin.setFont(new Font("TimesRoman", Font.PLAIN, 12));

    choiceSpin.add("3/2");
    choiceSpin.add("5/2");
    choiceSpin.add("7/2");
    choiceSpin.add("9/2");

    choiceSequence.add("V-V-V");
    choiceSequence.add("V-V-F");
    choiceSequence.add("V-F-V");
    choiceSequence.add("F-V-V");
    choiceSequence.add("V-F-F");
    choiceSequence.add("F-V-F");
    choiceSequence.add("F-F-V");

    //8 lines, 1 column, 0 horizontal space, and 10 vertical spaces
    panelSpinLabel.setLayout(new GridLayout(8, 1, 0, 10));
    panelSpinData.setLayout(new GridLayout(8, 1, 0, 10));
    panelSpinData2.setLayout(new GridLayout(8, 1, 0, 10));
    panelSpinData3.setLayout(new GridLayout(8, 1, 0, 10));
    panelSpinUnit.setLayout(new GridLayout(8, 1, 0, 10));

    panelSpinLabel.setBackground(Color.pink);
    panelSpinData.setBackground(Color.pink);
    panelSpinData2.setBackground(Color.pink);
    panelSpinData3.setBackground(Color.pink);
    panelSpinUnit.setBackground(Color.pink);

    panelSpinLabel.add(labelDate);
    panelSpinData.add(new Label(""));
    panelSpinData2.add(new Label(""));
    panelSpinData3.add(new Label(""));
    panelSpinUnit.add(new Label(""));

    panelSpinLabel.add(new Label(" Spin"));
    panelSpinData.add(choiceSpin);
    panelSpinData2.add(new Label(""));
    panelSpinData3.add(new Label(""));
    panelSpinUnit.add(new Label(""));

    panelSpinLabel.add(new Label(" RF field"));
    panelSpinData.add(textFieldOmegaRF);
    panelSpinData2.add(new Label("  kHz"));
    panelSpinData3.add(new Label(""));
    panelSpinUnit.add(new Label(""));

    panelSpinLabel.add(new Label(" OmegaQ"));
    panelSpinData.add(textFieldOmegaQ);
    panelSpinData2.add(new Label("  kHz"));
    panelSpinData3.add(new Label(""));
    panelSpinUnit.add(new Label(""));

    panelSpinLabel.add(choiceSequence);
    panelSpinData.add(new Label("Pulse-1"));
    panelSpinData2.add(new Label("Pulse-2"));
    panelSpinData3.add(new Label("Pulse-3"));
    panelSpinUnit.add(new Label(""));

    panelSpinLabel.add(new Label(" MinLength"));
    panelSpinData.add(textFieldPremiereDuree);
    panelSpinData2.add(textFieldPremiereDuree2);
    panelSpinData3.add(textFieldPremiereDuree3);
    panelSpinUnit.add(new Label("  µs"));

    panelSpinLabel.add(new Label(" MaxLength"));
    panelSpinData.add(textFieldDerniereDuree);
    panelSpinData2.add(textFieldDerniereDuree2);
    panelSpinData3.add(textFieldDerniereDuree3);
    panelSpinUnit.add(new Label("  µs"));

    panelSpinLabel.add(new Label(" Step"));
    panelSpinData.add(textFieldPas);
    panelSpinData2.add(textFieldPas2);
    panelSpinData3.add(textFieldPas3);
    panelSpinUnit.add(new Label("  µs"));

    textFieldPremiereDuree2.setVisible(false);
    textFieldDerniereDuree2.setVisible(false);
    textFieldPas2.setVisible(false);
    textFieldPremiereDuree3.setVisible(false);
    textFieldDerniereDuree3.setVisible(false);
    textFieldPas3.setVisible(false);

    //**************************  panelTransition  *****************************

    panelTransition.setBackground(Color.pink);
    panelTransition.setLayout(null);
    panelTransition.setFont(new Font("TimesRoman", Font.PLAIN, 12));

    labelPulse.setBounds(15, 7, 85, hautLB);
    panelTransition.add(labelPulse);
    labelDuree.setBounds(15, 27, 85, hautLB);
    panelTransition.add(labelDuree);
    labelLine.setBounds(100, 7, 85, hautLB);
    panelTransition.add(labelLine);
    labelIntensite.setBounds(100, 27, 100, hautLB);
    panelTransition.add(labelIntensite);

    panelSimulation.setLayout(new GridLayout(1, 2));
    panelSimulation.add(textAreaDuree);
    panelSimulation.add(textAreaIntensite);
    textAreaDuree.setEditable(false);
    textAreaIntensite.setEditable(false);

    scrollPaneSimulation.setBounds(10, 50, 180, 250);
    scrollPaneSimulation.add(panelSimulation);
    panelTransition.add(scrollPaneSimulation);

    labelOf.setBounds(90, 305, 85, hautLB);
    panelTransition.add(labelOf);

    choiceTransition.add("Central Transition");
    choiceTransition.add("Satellite Transitions");
    choiceTransition.add("All the Transitions");
    choiceTransition.select(0);
    choiceTransition.setBounds(10, 325, 180, 30);
    panelTransition.add(choiceTransition);

    buttonRun.setBounds(50, 355, 100, hautBouton);
    panelTransition.add(buttonRun);

    //****************************  panelFit  **********************************

    panelFit.setBackground(Color.orange);
    panelFit.setLayout(null);
    panelFit.setFont(new Font("TimesRoman", Font.PLAIN, 12));

    labelExperimental.setBounds(10, 7, 100, hautLB);
    panelFit.add(labelExperimental);
    labelExpIntensite.setBounds(10, 27, 100, hautLB);
    panelFit.add(labelExpIntensite);

    textAreaExpIntensite.setBounds(10, 50, 80, 160);
    panelFit.add(textAreaExpIntensite);

    textAreaParameter.setBounds(10, 212, 200, 140);
    panelFit.add(textAreaParameter);

    panelFitBouton.setBounds(10, 355, 200, hautBouton);
    panelFit.add(panelFitBouton);
    panelFitBouton.setLayout(new GridLayout(1, 2));
    panelFitBouton.add(buttonPrevious);
    panelFitBouton.add(buttonFit);
    buttonPrevious.setEnabled(false);

    choiceSimplex.add("1.1");              choiceSimplex.add("1.2");
    choiceSimplex.add("1.3");              choiceSimplex.add("1.4");
    choiceSimplex.select(2);

    panelFitEstim.setBounds(110, 5, 100, 206);
    //5 lines, 2 columns, zero horizontal and vertical spaces
    panelFitEstim.setLayout(new GridLayout(5, 2, 0, 0));
    panelFit.add(panelFitEstim);
    panelFitEstim.setBackground(Color.orange);
    panelFitEstim.setFont(new Font("TimesRoman", Font.PLAIN, 12));

    panelFitEstim.add(new Label("Simplex:"));
    panelFitEstim.add(choiceSimplex);
    panelFitEstim.add(new Label("RF field:"));
    panelFitEstim.add(new Label(""));
    panelFitEstim.add(textFieldOmegaRFEst);
    panelFitEstim.add(new Label("  kHz"));
    panelFitEstim.add(new Label("OmegaQ:"));
    panelFitEstim.add(new Label(""));
    panelFitEstim.add(textFieldOmegaQEst);
    panelFitEstim.add(new Label("  kHz"));

    //valeurs exemples
    String s5 = 0.0+"\n"+0.00613+"\n"+0.04721+"\n"+0.14971+"\n"+0.32492+"\n";
    s5 += 0.56569+"\n"+0.84721+"\n"+1.13178+"\n"+1.37638+"\n"+1.54163+"\n";
    s5 += 1.6+"\n"+1.54163+"\n"+1.37638+"\n"+1.13178+"\n"+0.84721+"\n";
    s5 += 0.56569+"\n"+0.32492+"\n"+0.14971+"\n"+0.04721+"\n"+0.00613+"\n";
    s5 += 0.0+"\n";
    textAreaExpIntensite.setText(s5);
  }//end of jbInit()

  private void ringSequence(int i, Nmr myNmrTmp,
                            double tp1, double tp2, double tp3,
               RealMat matHD, RealMat matR, RealMat matRt, RealMat matR2,
               RealMat matHDm, RealMat matRm, RealMat matRtm, RealMat matR2m) {
    ComplexMat   matHH, matHHC, matC1, matC2, matC3, matC4, matC5, matC6,
                 matC7, matC8, matC9, matC10, matC11, matC12, matC13,
                 matC14, matC15, matC16;

    //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    //-x +x +x sequence
    //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    // -x pulse
    matHH  = myNmrTmp.matriceHamilton(matHDm, tp1);
    matHHC = myNmrTmp.matConjugue(matHH);
    matC1  = myNmrTmp.mult(matR2m, matHH);   //action of -x pulse
    matC2  = myNmrTmp.mult(matHHC, matC1);   //action of -x pulse
    matC3  = myNmrTmp.mult(matC2, matRtm);   //back to the rotating frame
    matC4  = myNmrTmp.mult(matRm, matC3);    //back to the rotating frame
    // +x pulse
    matC5  = myNmrTmp.mult(matC4, matR);     //go to the PAS frame of matH
    matC6  = myNmrTmp.mult(matRt, matC5);    //go to the PAS frame of matH
    matHH  = myNmrTmp.matriceHamilton(matHD, tp2);
    matHHC = myNmrTmp.matConjugue(matHH);
    matC7  = myNmrTmp.mult(matC6, matHH);    //action of +x pulse
    matC8  = myNmrTmp.mult(matHHC, matC7);   //action of +x pulse
    matC9  = myNmrTmp.mult(matC8, matRt);    //back to the rotating frame
    matC10 = myNmrTmp.mult(matR, matC9);     //back to the rotating frame
    // +x pulse
    matC11 = myNmrTmp.mult(matC10, matR);    //go to the PAS frame of matH
    matC12 = myNmrTmp.mult(matRt, matC11);   //go to the PAS frame of matH
    matHH  = myNmrTmp.matriceHamilton(matHD, tp3);
    matHHC = myNmrTmp.matConjugue(matHH);
    matC13 = myNmrTmp.mult(matC12, matHH);   //action of +x pulse
    matC14 = myNmrTmp.mult(matHHC, matC13);  //action of +x pulse
    matC15 = myNmrTmp.mult(matC14, matRt);   //back to the rotating frame
    matC16 = myNmrTmp.mult(matR, matC15);    //back to the rotating frame
    singleOrAllTransition(1, i, matC16);

    //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    // -x +x -x sequence
    //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    // -x pulse
    matHH  = myNmrTmp.matriceHamilton(matHDm, tp1);
    matHHC = myNmrTmp.matConjugue(matHH);
    matC1  = myNmrTmp.mult(matR2m, matHH);   //action of -x pulse
    matC2  = myNmrTmp.mult(matHHC, matC1);   //action of -x pulse
    matC3  = myNmrTmp.mult(matC2, matRtm);   //back to the rotating frame
    matC4  = myNmrTmp.mult(matRm, matC3);    //back to the rotating frame
    // +x
    matC5  = myNmrTmp.mult(matC4, matR);     //go to the PAS frame of matH
    matC6  = myNmrTmp.mult(matRt, matC5);    //go to the PAS frame of matH
    matHH  = myNmrTmp.matriceHamilton(matHD, tp2);
    matHHC = myNmrTmp.matConjugue(matHH);
    matC7  = myNmrTmp.mult(matC6, matHH);    //action of +x pulse
    matC8  = myNmrTmp.mult(matHHC, matC7);   //action of +x pulse
    matC9  = myNmrTmp.mult(matC8, matRt);    //back to the rotating frame
    matC10 = myNmrTmp.mult(matR, matC9);     //back to the rotating frame
    // -x pulse
    matC11 = myNmrTmp.mult(matC10, matRm);   //go to the PAS frame of matHm
    matC12 = myNmrTmp.mult(matRtm, matC11);  //go to the PAS frame of matHm
    matHH  = myNmrTmp.matriceHamilton(matHDm, tp3);
    matHHC = myNmrTmp.matConjugue(matHH);
    matC13 = myNmrTmp.mult(matC12, matHH);   //action of -x pulse
    matC14 = myNmrTmp.mult(matHHC, matC13);  //action of -x pulse
    matC15 = myNmrTmp.mult(matC14, matRtm);  //back to the rotating frame
    matC16 = myNmrTmp.mult(matRm, matC15);   //back to the rotating frame
    singleOrAllTransition(-1, i, matC16);

    //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    // +x +x -x sequence
    //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    // +x pulse
    matHH  = myNmrTmp.matriceHamilton(matHD, tp1);
    matHHC = myNmrTmp.matConjugue(matHH);
    matC1  = myNmrTmp.mult(matR2, matHH);    //action of +x pulse
    matC2  = myNmrTmp.mult(matHHC, matC1);   //action of +x pulse
    matC3  = myNmrTmp.mult(matC2, matRt);    //back to the rotating frame
    matC4  = myNmrTmp.mult(matR, matC3);     //back to the rotating frame
    // +x pulse
    matC5  = myNmrTmp.mult(matC4, matR);     //go to the PAS frame of matH
    matC6  = myNmrTmp.mult(matRt, matC5);    //go to the PAS frame of matH
    matHH  = myNmrTmp.matriceHamilton(matHD, tp2);
    matHHC = myNmrTmp.matConjugue(matHH);
    matC7  = myNmrTmp.mult(matC6, matHH);    //action of +x pulse
    matC8  = myNmrTmp.mult(matHHC, matC7);   //action of +x pulse
    matC9  = myNmrTmp.mult(matC8, matRt);    //back to the rotating frame
    matC10 = myNmrTmp.mult(matR, matC9);     //back to the rotating frame
    // -x pulse
    matC11 = myNmrTmp.mult(matC10, matRm);   //go to the PAS frame of matHm
    matC12 = myNmrTmp.mult(matRtm, matC11);  //go to the PAS frame of matHm
    matHH  = myNmrTmp.matriceHamilton(matHDm, tp3);
    matHHC = myNmrTmp.matConjugue(matHH);
    matC13 = myNmrTmp.mult(matC12, matHH);   //action of -x pulse
    matC14 = myNmrTmp.mult(matHHC, matC13);  //action of -x pulse
    matC15 = myNmrTmp.mult(matC14, matRtm);  //back to the rotating frame
    matC16 = myNmrTmp.mult(matRm, matC15);   //back to the rotating frame
    singleOrAllTransition(1, i, matC16);

    //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    // +x +x +x sequence
    //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    // +x pulse
    matHH  = myNmrTmp.matriceHamilton(matHD, tp1);
    matHHC = myNmrTmp.matConjugue(matHH);
    matC1  = myNmrTmp.mult(matR2, matHH);   //action of +x pulse
    matC2  = myNmrTmp.mult(matHHC, matC1);  //action of +x pulse
    matC3  = myNmrTmp.mult(matC2, matRt);   //back to the rotating frame
    matC4  = myNmrTmp.mult(matR, matC3);    //back to the rotating frame
    // +x pulse
    matC5  = myNmrTmp.mult(matC4, matR);    //go to the PAS frame ofe matH
    matC6  = myNmrTmp.mult(matRt, matC5);   //go to the PAS frame of matH
    matHH  = myNmrTmp.matriceHamilton(matHD, tp2);
    matHHC = myNmrTmp.matConjugue(matHH);
    matC7  = myNmrTmp.mult(matC6, matHH);   //action of +x pulse
    matC8  = myNmrTmp.mult(matHHC, matC7);  //action of +x pulse
    matC9  = myNmrTmp.mult(matC8, matRt);   //back to the rotating frame
    matC10 = myNmrTmp.mult(matR, matC9);    //back to the rotating frame
    // +x pulse
    matC11 = myNmrTmp.mult(matC10, matR);   //go to the PAS frame of matH
    matC12 = myNmrTmp.mult(matRt, matC11);  //go to the PAS frame of matH
    matHH  = myNmrTmp.matriceHamilton(matHD, tp3);
    matHHC = myNmrTmp.matConjugue(matHH);
    matC13 = myNmrTmp.mult(matC12, matHH);  //action of +x pulse
    matC14 = myNmrTmp.mult(matHHC, matC13); //action of +x pulse
    matC15 = myNmrTmp.mult(matC14, matRt);  //back to the rotating frame
    matC16 = myNmrTmp.mult(matR, matC15);   //back to the rotating frame
    singleOrAllTransition(-1, i, matC16);
  }//end of ringSequence()

  private void calculIntensite(double omegaQTmp, double omegaRFTmp) {
    RealMat      matH, matHD, matR, matRt, matIz, matR1, matR2,
                 matHm, matHDm, matRm, matRtm, matIzm, matR1m, matR2m;
    double       tp;

    //OmegaQTmp and omegaRFTmp in kHz unit
    Nmr myNmr =  new Nmr(omegaQTmp, omegaRFTmp);
    //OmegaQ and omegaRF of myNmrTmp in radian/second unit

    //OmegaQTmp and -omegaRFTmp in kHz unit
    Nmr myNmrm = new Nmr(omegaQTmp, -omegaRFTmp);
    //OmegaQ and omegaRF of myNmrmTmp in radian/second unit

    for (int ii = 0; ii < nbou + 1; ii++) amplitude[ii] = 0.0;  //clear
    //x pulse
    matH  = myNmr.dataIn();          //find eigenvectors and eigenvalues of matH
    matHD = myNmr.jacRot(matH);           //matHD: the eigenvalue matrix of matH
    matR  = myNmr.getMatR();              //matR: the eigenvector matrix of matH
    matRt = RealMat.transpose(matR);      //matRt: the transposed matrix of matR
    matIz = myNmr.matriceIz();            //matrix of spin operator Iz
    matR1 = myNmr.mult(matIz, matR);      //matrix of spin operator Iz in the
    matR2 = myNmr.mult(matRt, matR1);     //PAS of matH

    // -x pulse
    matHm  = myNmrm.dataIn();       //find eigenvectors and eigenvalues of matHm
    matHDm = myNmrm.jacRot(matHm);      //matHDm: the eigenvalue matrix of matHm
    matRm  = myNmrm.getMatR();          //matRm: the eigenvector matrix of matHm
    matRtm = RealMat.transpose(matRm);  //matRtm: the transposed matrix of matRm
    matIzm = myNmrm.matriceIz();             //matrix of spin operator Iz
    matR1m = myNmrm.mult(matIzm, matRm);     //matrix of spin operator Iz in the
    matR2m = myNmrm.mult(matRtm, matR1m);    //PAS of  matHm

    switch (choiceSequence.getSelectedIndex()) {
      case 0:  //V-V-V
        for (int i = 0; i <= nbou; i++) {
          tp = dureePremiere + i*dureePas;
          ringSequence(i, myNmr, tp, tp, tp,
                       matHD, matR, matRt, matR2,
                       matHDm, matRm, matRtm, matR2m);
        }
        break;
      case 1:  //V-V-F
        for (int i = 0; i <= nbou; i++) {
          tp = dureePremiere + i*dureePas;
          ringSequence(i, myNmr, tp, tp, dureePremiere3,
                       matHD, matR, matRt, matR2,
                       matHDm, matRm, matRtm, matR2m);
        }
        break;
      case 2:  //V-F-V
        for (int i = 0; i <= nbou; i++) {
          tp = dureePremiere + i*dureePas;
          ringSequence(i, myNmr, tp, dureePremiere2, tp,
                       matHD, matR, matRt, matR2,
                       matHDm, matRm, matRtm, matR2m);
        }
        break;
      case 3:  //F-V-V
        for (int i = 0; i <= nbou; i++) {
          tp = dureePremiere + i*dureePas;
          ringSequence(i, myNmr, dureePremiere1, tp, tp,
                       matHD, matR, matRt, matR2,
                       matHDm, matRm, matRtm, matR2m);
        }
        break;
      case 4:  //V-F-F
        for (int i = 0; i <= nbou; i++) {
          tp = dureePremiere + i*dureePas;
          ringSequence(i, myNmr, tp, dureePremiere2, dureePremiere3,
                       matHD, matR, matRt, matR2,
                       matHDm, matRm, matRtm, matR2m);
        }
        break;
      case 5:  //F-V-F
        for (int i = 0; i <= nbou; i++) {
          tp = dureePremiere + i*dureePas;
          ringSequence(i, myNmr, dureePremiere1, tp, dureePremiere3,
                       matHD, matR, matRt, matR2,
                       matHDm, matRm, matRtm, matR2m);
        }
        break;
      case 6:  //F-F-V
        for (int i = 0; i <= nbou; i++) {
          tp = dureePremiere + i*dureePas;
          ringSequence(i, myNmr, dureePremiere1, dureePremiere2, tp,
                       matHD, matR, matRt, matR2,
                       matHDm, matRm, matRtm, matR2m);
        }
        break;
    }//end of switch
  }//end of calculIntensite()

  private void afficheTransition() {
    choiceTransition.removeAll();
    switch (choiceSpin.getSelectedIndex()) {
      case 0: //spin 3/2
              choiceTransition.add("Central Transition");
              choiceTransition.add("Satellite Transitions");
              choiceTransition.add("All the Transitions");
              break;
      case 1: //spin 5/2
              choiceTransition.add("Central Transition");
              choiceTransition.add("Inner Satellite Transitions");
              choiceTransition.add("Outer Satellite Transitions");
              choiceTransition.add("All the Transitions");
              break;
      case 2: //spin 7/2
              choiceTransition.add("Central Transition");
              choiceTransition.add("Inner Satellite Transitions");
              choiceTransition.add("Medium Satellite Transitions");
              choiceTransition.add("Outer Satellite Transitions");
              choiceTransition.add("All the Transitions");
              break;
      case 3: //spin 9/2
              choiceTransition.add("Central Transition");
              choiceTransition.add("Inner Satellite Transitions");
              choiceTransition.add("Medium Satellite Transitions");
              choiceTransition.add("Next Satellite Transitions");
              choiceTransition.add("Outer Satellite Transitions");
              choiceTransition.add("All the Transitions");
              break;
      }//end of switch
    choiceTransition.select(0);
    choix ='C';
  }//end of afficheTransition()

  private void normalisationSignal() {
    switch (choiceSpin.getSelectedIndex()) {
      case 0: ComplexMat.setTailleMatrice(4);           coeff = 5.0;
              switch (choix) {
                case 'C': ligne = 2;  pop =   Math.sqrt(4);   break;
                case 'I': ligne = 1;  pop = 2*Math.sqrt(3);   break;
              }
              break;
      case 1: ComplexMat.setTailleMatrice(6);      coeff = 35.0/2.0;
              switch (choix) {
                case 'C': ligne = 3;  pop =   Math.sqrt(9);   break;
                case 'I': ligne = 2;  pop = 2*Math.sqrt(8);   break;
                case 'O': ligne = 1;  pop = 2*Math.sqrt(5);   break;
              }
              break;
      case 2: ComplexMat.setTailleMatrice(8);          coeff = 42.0;
              switch (choix) {
                case 'C': ligne = 4;  pop =   Math.sqrt(16);  break;
                case 'I': ligne = 3;  pop = 2*Math.sqrt(15);  break;
                case 'M': ligne = 2;  pop = 2*Math.sqrt(12);  break;
                case 'O': ligne = 1;  pop = 2*Math.sqrt(7);   break;
              }
              break;
      case 3: ComplexMat.setTailleMatrice(10);    coeff = 165.0/2.0;
              switch (choix) {
                case 'C': ligne = 5;  pop =   Math.sqrt(25);  break;
                case 'I': ligne = 4;  pop = 2*Math.sqrt(24);  break;
                case 'M': ligne = 3;  pop = 2*Math.sqrt(21);  break;
                case 'N': ligne = 2;  pop = 2*Math.sqrt(16);  break;
                case 'O': ligne = 1;  pop = 2*Math.sqrt(9);   break;
              }
              break;
    }//end of switch
  }//end of normalisationSignal()

  /**Start the applet*/
  public void start() {
  //*********
  //buttonRun
  //*********
    buttonRun.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        double milli = 0.001;
        normalisationSignal();
        /*transform pulse durations from microsecond unit to millisecond unit,
        because the interactions are in kHz unit*/
        switch (choiceSequence.getSelectedIndex()) {
          case 0:  //V-V-V
            dureeFin =         milli*Double.valueOf(textFieldDerniereDuree.
                               getText()).doubleValue();
            dureePremiere =    milli*Double.valueOf(textFieldPremiereDuree.
                               getText()).doubleValue();
            dureePas =         milli*Double.valueOf(textFieldPas.
                               getText()).doubleValue();
            break;
          case 1:  //V-V-F
            dureeFin =         milli*Double.valueOf(textFieldDerniereDuree.
                               getText()).doubleValue();
            dureePremiere =    milli*Double.valueOf(textFieldPremiereDuree.
                               getText()).doubleValue();
            dureePas =         milli*Double.valueOf(textFieldPas.
                               getText()).doubleValue();
            dureePremiere3 =   milli*Double.valueOf(textFieldPremiereDuree3.
                               getText()).doubleValue();
            break;
          case 2:  //V-F-V
            dureeFin =         milli*Double.valueOf(textFieldDerniereDuree.
                               getText()).doubleValue();
            dureePremiere =    milli*Double.valueOf(textFieldPremiereDuree.
                               getText()).doubleValue();
            dureePas =         milli*Double.valueOf(textFieldPas.
                               getText()).doubleValue();
            dureePremiere2 =   milli*Double.valueOf(textFieldPremiereDuree2.
                               getText()).doubleValue();
            break;
          case 3:  //F-V-V
            dureePremiere1 =   milli*Double.valueOf(textFieldPremiereDuree.
                               getText()).doubleValue();
            dureeFin =         milli*Double.valueOf(textFieldDerniereDuree2.
                               getText()).doubleValue();
            dureePremiere =    milli*Double.valueOf(textFieldPremiereDuree2.
                               getText()).doubleValue();
            dureePas =         milli*Double.valueOf(textFieldPas2.
                               getText()).doubleValue();
            break;
          case 4:  //V-F-F
            dureeFin =         milli*Double.valueOf(textFieldDerniereDuree.
                               getText()).doubleValue();
            dureePremiere =    milli*Double.valueOf(textFieldPremiereDuree.
                               getText()).doubleValue();
            dureePas =         milli*Double.valueOf(textFieldPas.
                               getText()).doubleValue();
            dureePremiere2 =   milli*Double.valueOf(textFieldPremiereDuree2.
                               getText()).doubleValue();
            dureePremiere3 =   milli*Double.valueOf(textFieldPremiereDuree3.
                               getText()).doubleValue();
            break;
          case 5:  //F-V-F
            dureePremiere1 =   milli*Double.valueOf(textFieldPremiereDuree.
                               getText()).doubleValue();
            dureeFin =         milli*Double.valueOf(textFieldDerniereDuree2.
                               getText()).doubleValue();
            dureePremiere =    milli*Double.valueOf(textFieldPremiereDuree2.
                               getText()).doubleValue();
            dureePas =         milli*Double.valueOf(textFieldPas2.
                               getText()).doubleValue();
            dureePremiere3 =   milli*Double.valueOf(textFieldPremiereDuree3.
                               getText()).doubleValue();
            break;
          case 6:  //F-F-V
            dureePremiere1 =   milli*Double.valueOf(textFieldPremiereDuree.
                               getText()).doubleValue();
            dureePremiere2 =   milli*Double.valueOf(textFieldPremiereDuree2.
                               getText()).doubleValue();
            dureeFin =         milli*Double.valueOf(textFieldDerniereDuree3.
                               getText()).doubleValue();
            dureePremiere =    milli*Double.valueOf(textFieldPremiereDuree3.
                               getText()).doubleValue();
            dureePas =         milli*Double.valueOf(textFieldPas3.
                               getText()).doubleValue();
            break;
        } //end of switch
        nbou =             (int)((dureeFin - dureePremiere)/dureePas);
        amplitude =        new double[nbou + 1];
        listExpIntensity = new double[nbou + 1];
        calculIntensite(Double.valueOf(textFieldOmegaQ.getText()).doubleValue(),
                      Double.valueOf(textFieldOmegaRF.getText()).doubleValue());
        scrollPaneSimulation.setScrollPosition(0, 0);   //top part of scrollPane

        //*******show simulated line intensity versus the pulse duration********
        double tp = 0;
        String s = "", s2 = "";
        textAreaIntensite.setText(""); //clear intensity
        textAreaDuree.setText("");     //clear pulse duration
        for (int i = 0; i <= nbou; i++) {
          tp = dureePremiere + i*dureePas;
          s = textAreaIntensite.getText()
              + Math.round(100000*amplitude[i])/100000.0 + "\n";
          textAreaIntensite.setText(s);
          s2 = textAreaDuree.getText() + Math.round(100000*tp)/100.0 + "\n";
          textAreaDuree.setText(s2);
        }//end of for i
        //**********************************************************************

        panelFit.setVisible(true);
        panelFitEstim.setVisible(true);
      }
    });

  //*********
  //buttonFit
  //*********
    buttonFit.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        /*thread for starting the simplex procedure with run() and
        for plotting the fitting curves*/
        Thread th = null;

        if (buttonFit.getLabel() == "Fit") {
          //convert experimental intensities into numbers
          String s = textAreaExpIntensite.getText(),     s1 = "";
          int spaceAt = 0, startingForm = 0, ip = 0;
          while (true) {
            spaceAt = s.indexOf("\n", startingForm);
            if (spaceAt == -1) break;
            s1 = s.substring(startingForm, spaceAt);
            listExpIntensity[ip] = Double.valueOf(s1).doubleValue();
            startingForm = spaceAt + 1;
            ip++;
          }
          if (ip != nbou + 1) {   //check the number of data
            textAreaParameter.setText("");
            textAreaParameter.append("The number of experimental" + "\n");
            textAreaParameter.append("intensities is wrong!!!" + "\n");
            textAreaParameter.append("May be type enter key" + "\n");
            textAreaParameter.append("for the last intensity data!!!");
          }
          else {  //start fitting
            panelFit.setLocation(300, 0);
            setBackground(Color.pink);
            panelTransition.setVisible(false);
            panelSpin.setVisible(false);
            panelBlanc.setBounds(520 ,0, 240, hautPanel);
            add(panelBlanc);
            panelBlanc.setVisible(true);
            panelBlanc.setBackground(Color.white);
            buttonFit.setLabel("StopFit");
            buttonPrevious.setEnabled(false);
            textAreaParameter.setText("");
            double alpha =
              Double.valueOf(choiceSimplex.getSelectedItem()).doubleValue();
            double val1 =
              Double.valueOf(textFieldOmegaQEst.getText()).doubleValue();
            double val2 =
              Double.valueOf(textFieldOmegaRFEst.getText()).doubleValue();
            //find the maximum values in listExpIntensity[] and in amplitude[]
            double maxExp = 0, maxCal = 0;
            for (int i = 0; i < nbou + 1; i++)
              if (Math.abs(listExpIntensity[i]) > maxExp)
                  maxExp = Math.abs(listExpIntensity[i]);
            for (int i = 0; i < nbou + 1; i++)
              if (Math.abs(amplitude[i]) > maxCal)
                maxCal = Math.abs(amplitude[i]);
            double val3 =  maxExp/maxCal;  //scaling
            choiceSimplex.setEnabled(false);
            textFieldOmegaRFEst.setEnabled(false);
            textFieldOmegaQEst.setEnabled(false);
            textAreaExpIntensite.setEnabled(false);
            normalisationSignal();
            //initial parameters for simplex procedure
            matEstimation[0][0] = val1;       matEstimation[0][1] = val2;
            matEstimation[0][2] = val3;       matEstimation[1][0] = alpha*val1;
            matEstimation[1][1] = val2;       matEstimation[1][2] = val3;
            matEstimation[2][0] = val1;       matEstimation[2][1] = alpha*val2;
            matEstimation[2][2] = val3;       matEstimation[3][0] = val1;
            matEstimation[3][1] = val2;       matEstimation[3][2] = alpha*val3;

            th = new Thread(RingXtalJDK118.this);
            th.start();

            buttonGraph.setLabel("DeactivateGraph");
            buttonGraph.setVisible(true);
            buttonGraph.setEnabled(true);
            labelAdvice.setVisible(true);
            showCurve = true;
            stopFit = false;
          }
        }
        else {  //stop fitting
          stopFit = true;
          th = null;
          buttonPrevious.setEnabled(true);
          buttonFit.setLabel("Fit");
          choiceSimplex.setEnabled(true);
          textFieldOmegaRFEst.setEnabled(true);
          textFieldOmegaQEst.setEnabled(true);
          textAreaExpIntensite.setEnabled(true);
          buttonGraph.setEnabled(false);
          labelAdvice.setVisible(false);
        }
      }
    });

  //**************
  //buttonPrevious
  //**************
    buttonPrevious.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        panelSpin.setVisible(true);
        panelBlanc.setVisible(false);
        // widths of panelTransition and panelFit + 100
        panelTransition.setLocation(320, 0);
        panelTransition.setVisible(true);
        panelFit.setLocation(540, 0);
        buttonPrevious.setEnabled(false);
        setBackground(Color.white);
        panelSpin.setBackground(Color.pink);
        panelFit.setBackground(Color.orange);
        panelTransition.setBackground(Color.pink);
        buttonGraph.setVisible(false);
        buttonFit.setLabel("Fit");
        buttonRun.setEnabled(true);
      }
    });

  //***********
  //buttonGraph
  //***********
    buttonGraph.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        if (buttonGraph.getLabel() == "DeactivateGraph") {
          showCurve = false;
          buttonGraph.setLabel("ActivateGraph");
          labelAdvice.setVisible(false);
        }
        else {
          showCurve = true;
          buttonGraph.setLabel("DeactivateGraph");
          labelAdvice.setVisible(true);
        }
      }
    });

  //**********
  //choiceSpin
  //**********
    choiceSpin.addItemListener(new java.awt.event.ItemListener() {
      public void itemStateChanged(ItemEvent e) {
        textAreaIntensite.setText("");  //clear intensity
        textAreaDuree.setText("");      //clear pulse duration
        afficheTransition();
      }
    });

  //**************
  //choiceSequence
  //**************
    choiceSequence.addItemListener(new java.awt.event.ItemListener() {
      public void itemStateChanged(ItemEvent e) {
        switch (choiceSequence.getSelectedIndex()) {
          //V-V-V
          case 0: textFieldPremiereDuree.setVisible(true);
                  textFieldDerniereDuree.setVisible(true);
                  textFieldPas.setVisible(true);
                  textFieldPremiereDuree2.setVisible(false);
                  textFieldDerniereDuree2.setVisible(false);
                  textFieldPas2.setVisible(false);
                  textFieldPremiereDuree3.setVisible(false);
                  textFieldDerniereDuree3.setVisible(false);
                  textFieldPas3.setVisible(false);
                  break;
          //V-V-F
          case 1: textFieldPremiereDuree.setVisible(true);
                  textFieldDerniereDuree.setVisible(true);
                  textFieldPas.setVisible(true);
                  textFieldPremiereDuree2.setVisible(false);
                  textFieldDerniereDuree2.setVisible(false);
                  textFieldPas2.setVisible(false);
                  textFieldPremiereDuree3.setVisible(true);
                  textFieldDerniereDuree3.setVisible(false);
                  textFieldPas3.setVisible(false);
                  break;
          //V-F-V
          case 2: textFieldPremiereDuree.setVisible(true);
                  textFieldDerniereDuree.setVisible(true);
                  textFieldPas.setVisible(true);
                  textFieldPremiereDuree2.setVisible(true);
                  textFieldDerniereDuree2.setVisible(false);
                  textFieldPas2.setVisible(false);
                  textFieldPremiereDuree3.setVisible(false);
                  textFieldDerniereDuree3.setVisible(false);
                  textFieldPas3.setVisible(false);
                  break;
          //F-V-V
          case 3: textFieldPremiereDuree.setVisible(true);
                  textFieldDerniereDuree.setVisible(false);
                  textFieldPas.setVisible(false);
                  textFieldPremiereDuree2.setVisible(true);
                  textFieldDerniereDuree2.setVisible(true);
                  textFieldPas2.setVisible(true);
                  textFieldPremiereDuree3.setVisible(false);
                  textFieldDerniereDuree3.setVisible(false);
                  textFieldPas3.setVisible(false);
                  break;
          //V-F-F
          case 4: textFieldPremiereDuree.setVisible(true);
                  textFieldDerniereDuree.setVisible(true);
                  textFieldPas.setVisible(true);
                  textFieldPremiereDuree2.setVisible(true);
                  textFieldDerniereDuree2.setVisible(false);
                  textFieldPas2.setVisible(false);
                  textFieldPremiereDuree3.setVisible(true);
                  textFieldDerniereDuree3.setVisible(false);
                  textFieldPas3.setVisible(false);
                  break;
          //F-V-F
          case 5: textFieldPremiereDuree.setVisible(true);
                  textFieldDerniereDuree.setVisible(false);
                  textFieldPas.setVisible(false);
                  textFieldPremiereDuree2.setVisible(true);
                  textFieldDerniereDuree2.setVisible(true);
                  textFieldPas2.setVisible(true);
                  textFieldPremiereDuree3.setVisible(true);
                  textFieldDerniereDuree3.setVisible(false);
                  textFieldPas3.setVisible(false);
                  break;
          //F-F-V
          case 6: textFieldPremiereDuree.setVisible(true);
                  textFieldDerniereDuree.setVisible(false);
                  textFieldPas.setVisible(false);
                  textFieldPremiereDuree2.setVisible(true);
                  textFieldDerniereDuree2.setVisible(false);
                  textFieldPas2.setVisible(false);
                  textFieldPremiereDuree3.setVisible(true);
                  textFieldDerniereDuree3.setVisible(true);
                  textFieldPas3.setVisible(true);
                  break;
        }
      }
    });

  //****************
  //choiceTransition
  //****************
    choiceTransition.addItemListener(new java.awt.event.ItemListener() {
      public void itemStateChanged(ItemEvent e) {
        String rangTransition = choiceTransition.getSelectedItem();
        if (rangTransition == "Central Transition")
            choix = 'C';
          else if (rangTransition == "Satellite Transitions")
              choix = 'I';
            else if (rangTransition == "Inner Satellite Transitions")
                choix = 'I';
              else if (rangTransition == "Medium Satellite Transitions")
                  choix = 'M';
                else if (rangTransition == "Next Satellite Transitions")
                    choix = 'N';
                  else if (rangTransition == "Outer Satellite Transitions")
                      choix = 'O';
                    else if (rangTransition == "All the Transitions")
                        choix = 'A';
        textAreaIntensite.setText("");  //clear intensity
        textAreaDuree.setText("");      //clear pulse duration
      }
    });
  }//end of start()

  /**Stop the applet*/
  public void stop() {
  }

  /**Destroy the applet*/
  public void destroy() {
  }

  /**Get Applet information*/
  public String getAppletInfo() {
    return "Applet Information";
  }

  /**Get parameter info*/
  public String[][] getParameterInfo() {
    return null;
  }

  private void singleOrAllTransition(int signe, int j, ComplexMat matC) {
    if (choix != 'A') amplitude[j] += signe*(pop/coeff)
                                      *matC.im[ligne][ligne - 1];
    else switch (choiceSpin.getSelectedIndex()) {
      case 0: amplitude[j] += signe*(2*matC.im[2][1]
                              + 2*Math.sqrt(3)*matC.im[1][0])/coeff;
              break;
      case 1: amplitude[j] += signe*(3*matC.im[3][2]
                              + 2*Math.sqrt(8)*matC.im[2][1]
                              + 2*Math.sqrt(5)*matC.im[1][0])/coeff;
              break;
      case 2: amplitude[j] += signe*(4*matC.im[4][3]
                              + 2*Math.sqrt(15)*matC.im[3][2]
                              + 2*Math.sqrt(12)*matC.im[2][1]
                              + 2*Math.sqrt(7)*matC.im[1][0])/coeff;
              break;
      case 3: amplitude[j] += signe*(5*matC.im[5][4]
                              + 2*Math.sqrt(24)*matC.im[4][3]
                              + 2*Math.sqrt(21)*matC.im[3][2]
                              + 2*Math.sqrt(16)*matC.im[2][1]
                              + 2*Math.sqrt(9)*matC.im[1][0])/coeff;
              break;
    }//end of switch
  }//end of singleOrAllTransition()

  private double mySimplexFonction(double omegaQFit, double omegaRFFit,
                                   double norme) {
    double sqsum = 0;
    calculIntensite(omegaQFit, omegaRFFit);
    for (int i = 0; i <= nbou; i++) {
      double tmp = norme*amplitude[i] - listExpIntensity[i];
      sqsum += tmp*tmp;
    }
    return sqsum;
  }//end of mySimplexFonction()

  private void plotCourbe(double b0, double b1, double b2) {
    //plot experimental intensity data and the fitting curve
    Graph("Ringing to crystal", "tp (µs)", "S(tp)");
    double inc;
    setSymbol(true);
    setLine(false);
    setColor(blue);
    setTitle("experimental");
    for (int i = 0; i <= nbou; i++) {
      inc = Math.round(100000*(dureePremiere + i*dureePas))/100.0;
      add(inc, listExpIntensity[i]);
    }
    nextGraph();
    setColor(black);
    setTitle("fit");
    calculIntensite(b0, b1);
    for (int i = 0; i <= nbou; i++) {
      inc = Math.round(100000*(dureePremiere + i*dureePas))/100.0;
      add(inc, b2*amplitude[i]);
    }
    showGraph();
  }//end of plotCourbe()

  public void run() {        //run the simplex procedure
  /* The flexible simplex method allows you to find the minimum for a function
   * with multiple variables. The method obtains the minimum for a function
   * with N variables by examining the function values at N + 1 points.
   * This method locates the points with the best and worst values
   * then attempts to replace the worst-value point with a better point.
   * This replacement process involves expanding and contracting the simplex
   * near the worst-value point to determine a better replacement point.
   * The iterations of the method shrinks the multidimensional simplex around
   * the minimum point.
   * Given
   * # N variables that evaluate function f(X)
   * # The matrix X, which contains N + 1 rows and N columns
   * # The array of function values, Y(containing N + 1 values)
   * # The maximum number of iterations, MAXITER
   * # The reflection factor, which is a positive value that may be unity
   * # The expansion factor, which is greater than one (usually two)
   * # The contraction factor, a value between zero and one (ususally 0.5)
   */
    //(1) set Iter = 0
    //(2) set P = N + 1

    //the 4 constants used in simplex procedure
    final int REFLECTFACT = 1;               final int EXPANDFACT = 2;
    final double CONTRACTFACT = 0.5;         final int MAXITER = 1000;

    int    numIter = 0, numPoints = numVars + 1, worstI = 0, bestI = 0;
    double y1 = 0, y2 = 0;
    //(5) set the convergence flag to false
    boolean flag = false;
    double y[] = new double[numVars + 1];

    //(3) allocate dynamic arrays x1, x2 and centroid to contain N elements
    double x1[] = new double[numVars];
    double x2[] = new double[numVars];
    double centroid[] = new double[numVars];

    //(4)calculate the values for y() using x1()
    for (int i = 0; i < numPoints; i++) {
      for (int j = 0; j < numVars; j++) x1[j] = matEstimation[i][j];
      y[i] = mySimplexFonction(x1[0], x1[1], x1[2]);
    }

    //*************************  boucle while  *********************************

    //(6) repeat the next step while Iter < M and the convergence flag is false
    while ((numIter < MAXITER) && (!stopFit)) {
      String sx = "";
      textAreaParameter.setText("");
      sx = "Iteration: " + numIter + " \n";
      textAreaParameter.append(sx);

      numIter += 1;      //(6.1) increment Iter

      //(6.2) find the indices of the worst A and best points
      worstI = 0;      bestI = 0;
      for (int i = 1; i < numPoints; i++) {
        if (y[i] < y[bestI])        bestI = i;
        else if (y[i] > y[worstI])  worstI = i;
      }

      //provide the fitting parameters
      sx = Math.round(1000*matEstimation[bestI][1])/1000.0
          + " ( " + Math.round(1000*matEstimation[worstI][1])/1000.0
          + " ) kHz\n";
      textAreaParameter.append("RF field: " + sx);
      sx = Math.round(1000*matEstimation[bestI][0])/1000.0
          + " ( " + Math.round(1000*matEstimation[worstI][0])/1000.0
          + " ) kHz\n";
      textAreaParameter.append("OmegaQ: " + sx);
      sx = Math.round(1000*matEstimation[bestI][2])/1000.0
          + " ( " + Math.round(1000*matEstimation[worstI][2])/1000.0
          + " )\n";
      textAreaParameter.append("Scale: " + sx);
      sx = y[bestI] + "\n";
      textAreaParameter.append(sx);
      sx = y[worstI] + "\n";
      textAreaParameter.append(sx);

      if (showCurve) {
        try {Thread.sleep(10);}
        catch (InterruptedException e) {}
        //plotCourbe should be located after try otherwise problem with Netscape
        plotCourbe(matEstimation[worstI][0], matEstimation[worstI][1],
                   matEstimation[worstI][2]);
      }

      //(6.3) calculate centroid (exclude the worst point A)
      //= center of gravity G
      for (int i = 0; i < numVars; i++) {
        centroid[i] = 0;
        for (int j = 0; j < numPoints; j++) {
          if (j != worstI) centroid[i] += matEstimation[j][i];
        }
        centroid[i] /= numVars;
      }

      //(6.4) calculate reflected point A'
      //(symmetrical point of A relative to G): A' = 2*G - A
      for (int i = 0; i < numVars; i++)
        x1[i] = (1 + REFLECTFACT) * centroid[i]
                 - REFLECTFACT * matEstimation[worstI][i];

      //(6.5) set y1 = function value at point x1 or f(A')
      y1 = mySimplexFonction(x1[0], x1[1], x1[2]);

      //************************** beginning of if  ****************************

      //(6.6) if y1 or f(A') < best y, that is,
      //f(A') is the best value found so far
      if (y1 < y[bestI]) {       //perform the following tasks:
        //(6.6.1) calculate the expandeded point x2 or A" = 2A' - G:
        //a point twice as far from G as A'
        for (int k = 0; k < numVars; k++)
          x2[k] = (1 + EXPANDFACT) * x1[k] - EXPANDFACT * centroid[k];

        //(6.6.2) set y2 = function value at point x2, or f(A")
        y2 = mySimplexFonction(x2[0], x2[1], x2[2]);

        //(6.6.3) if y2 or f(A") < best y
        if (y2 < y[bestI]) { //then replace worst point matEstimation
                             //with point x2 or A" and resume at step 7
          for (int m = 0; m < numVars; m++) matEstimation[worstI][m] = x2[m];
        }
        else {  //else replace worst point matEstimation with point x1 or A'
                //and resume at step 7
          for (int n = 0; n < numVars; n++) matEstimation[worstI][n] = x1[n];
        }
      }

      //******************************* else ***********************************

      else {    //(6.7) y1 or f(A') >= best y
        flag = true;
        for (int q = 0; q < numPoints; q++) {
          if ((q != worstI) && (y1 <= y[q])) {
            flag = false;  //f(A') is between best y and the others y, except A
            break;         //exit for
          }
        }

        if (flag) {//y1 or f(A') is not between best y and the others y, except A
          if (y1 < y[worstI]) {     //f(A') is between best y and f(A),
            //(6.7.1) replace worst point by x1 or A'
            for (int p = 0; p < numVars; p++) matEstimation[worstI][p] = x1[p];
            y[worstI] = y1;
          }
          //f(A') >= f(A)
          //(6.7.2) calculate contracted point x2 or
          //B = (A + G)/2 or B = (A' + G)/2
          for (int s = 0; s < numVars; s ++)
            x2[s] = CONTRACTFACT * matEstimation[worstI][s]
                    + (1 - CONTRACTFACT) * centroid[s];
          //(6.7.3) set y2 = function value at point x2 or f(B)
          y2 = mySimplexFonction(x2[0], x2[1], x2[2]);

          if (y2 > y[worstI]) { //f(B)>f(A) or f(B)>f(A'),
                                //ALL WE DID ARE NOT USEFUL
            //store best matEstimation in x2
            for (int u = 0; u < numVars; u++) x2[u] = matEstimation[bestI][u];
            //and build a new simplex obtained by dividing
            //all edges leading to the point yielding the best value by 2
            for (int j = 0; j < numPoints; j++)
              for (int q = 0; q < numVars; q++)
                matEstimation[j][q] = 0.5 * (x2[q] + matEstimation[j][q]);
          }  //resume 7
          else { //(else of y2), f(B)<f(A) ou f(B)<f(A'),
                 //replace worst point or A or A' by x2 or B,
            for (int w = 0; w < numVars; w++) matEstimation[worstI][w] = x2[w];
          } //resume 7
        }
        else {   //flag = false,
                 //f(A') est compris entre best y et les autres Y sauf A
                 //replace worst point by x1 or A' and resume 7
          for (int z = 0; z < numVars; z++) matEstimation[worstI][z] = x1[z];
        } //end of flag
      }

      //**************************** end of if *********************************

      //(7) calculate the values for y() using x1
      for (int i = 0; i < numPoints; i++) {
        for (int j = 0; j < numVars; j++) x1[j] = matEstimation[i][j];
        y[i] = mySimplexFonction(x1[0], x1[1], x1[2]);
      }
    }//end of while
  }//end of run()

}//end of class RingXtalJDK118