package ppmrmn;

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

public class SolomonEkoXtalJDK118 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
                  colonne = 2,
                  ligneST = 1;
  private boolean stopFit = false,
                  showCurve = true;
  private double  coeff = 5,            //for signal normalisation use
                  pop = 2*Math.sqrt(3), //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,
                  amplitude[] = {0.0},     //FID intensity
                  amplitudeReal[] = {0.0}, //real part of the FID intensity
                  amplitudeImag[] = {0.0}, //imaginary part of the 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 700LX390H 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, and panelSpinUnit

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

  //panelTransition includes panelSimulation, panelCheckgroup,
  //                         and scrollPaneSimulation

  Panel panelTransition = new Panel();   Panel panelSimulation = new Panel();
  Panel panelCheckgroup = 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 choicePulseSequence =  new Choice();
  Choice choiceSpin =           new Choice();
  Choice choiceSequence =       new Choice();
  Choice choiceTransition =     new Choice();
  Choice choiceEkoPosition =    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");

  CheckboxGroup checkboxgroup = new CheckboxGroup();
  Checkbox checkboxReal = new Checkbox("real part", checkboxgroup, false);
  Checkbox checkboxImag = new Checkbox("imaginary part", checkboxgroup, true);

  Label labelDate =         new Label("30-01-04");
  Label labelPulse =        new Label("Pulse");
  Label labelDuree =        new Label("Length (µs)");
  Label labelLine =         new Label("Line");
  Label labelIntensite =    new Label("Intensity");
  Label labelTransition =   new Label("Nature of the echo:");
  Label labelPosition =     new Label("Position of the echo:");
  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("5.0");

  TextField textFieldDerniereDuree2 = new TextField("10.0");
  TextField textFieldPas2 =           new TextField("0.5");
  TextField textFieldPremiereDuree2 = new TextField("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);
         /*imaginary part of the echo amplitude*/
  TextArea textAreaIntensite =     new TextArea("", 100, 7,
                                               TextArea.SCROLLBARS_NONE);
         /*real part of the echo amplitude*/
  TextArea textAreaIntensiteReel = 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 SolomonEkoXtalJDK118() {
  }

  /**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, 260, 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);
    panelSpinUnit.setBounds(210, 0, 50, hautPanel-3);
    panelSpin.add(panelSpinUnit);

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

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

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

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

    choicePulseSequence.add("X-X");
    choicePulseSequence.add("Y-X");

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

    choiceSequence.add("A(p1)B()");
    choiceSequence.add("A()B(p2)");
    choiceSequence.select(1);

    //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));
    panelSpinUnit.setLayout(new GridLayout(8, 1, 0, 10));

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

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

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

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

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

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

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

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

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

    textFieldDerniereDuree.setVisible(false);
    textFieldPas.setVisible(false);

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

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

    //labels of the simulated line intensity
    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);

    //simulation scroll pane
    panelSimulation.setLayout(new GridLayout(1, 2));
    panelSimulation.add(textAreaDuree);
    panelSimulation.add(textAreaIntensite);
    textAreaDuree.setEditable(false);
    textAreaIntensite.setEditable(false);
    scrollPaneSimulation.setBounds(10, 50, 180, 150);
    scrollPaneSimulation.add(panelSimulation);
    panelTransition.add(scrollPaneSimulation);

    //imaginary and real echo amplitude check group panel
    panelCheckgroup.setBounds(110, 215, 110, 30);
    panelTransition.add(panelCheckgroup);
    panelCheckgroup.setBackground(Color.pink);
    panelCheckgroup.setLayout(new GridLayout(2, 1)); //2 lines, 1 column
    panelCheckgroup.add(checkboxReal);
    panelCheckgroup.add(checkboxImag);
    checkboxReal.setBackground(Color.pink);
    checkboxImag.setBackground(Color.pink);
    panelCheckgroup.setVisible(false);

    //transition choice
    labelTransition.setBounds(10, 250, 180, hautLB);
    panelTransition.add(labelTransition);
    choiceTransition.add("Satellite Transitions");
    choiceTransition.setBounds(10, 275, 180, 20);
    panelTransition.add(choiceTransition);

    //echo position choice
    labelPosition.setBounds(10, 300, 180, hautLB);
    panelTransition.add(labelPosition);
    choiceEkoPosition.add("tau2");
    choiceEkoPosition.setBounds(10, 325, 180, 20);
    panelTransition.add(choiceEkoPosition);

    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.01088+"\n"+-0.04087+"\n"+-0.08264+"\n";
    s5 += -0.12578+"\n"+-0.1591+"\n"+-0.17312+"\n"+-0.16219+"\n"+-0.12578+"\n";
    s5 += -0.06867+"\n"+0.0+"\n"+0.06867+"\n"+0.12578+"\n"+0.16219+"\n";
    s5 += 0.17312+"\n"+0.1591+"\n"+0.12578+"\n"+0.08264+"\n";
    s5 += 0.04087+"\n"+0.01088+"\n"+0.0+"\n";
    textAreaExpIntensite.setText(s5);
  }//end of JbInit()

  private void solomonEkoSequence(int i, Nmr myNmrTmp, double tp1, double tp2,
               RealMat matHD, RealMat matR, RealMat matRt, RealMat matR2) {
    ComplexMat   matHH, matHHC, matC1, matC2, matC3, matC4, matC5, matC6,
                 matC7, matC8, matC9, matC10, matCz;

    //first +x pulse
    matHH  = myNmrTmp.matriceHamilton(matHD, tp1);
    matHHC = myNmrTmp.matConjugue(matHH);
    matC1  = myNmrTmp.mult(matR2, matHH);    //action of the first +x pulse
    matC2  = myNmrTmp.mult(matHHC, matC1);   //action of the first +x pulse
    matC3  = myNmrTmp.mult(matC2, matRt);    //back to the
    matC4  = myNmrTmp.mult(matR, matC3);     //rotating frame

    if (choicePulseSequence.getSelectedIndex() == 1)
      matC4 = myNmrTmp.matRotation(matC4, Math.PI/2);
    matCz  = myNmrTmp.matQuatre(matC4, ligne, colonne);

    //action of the second +x pulse
    matC5  = myNmrTmp.mult(matCz, matR);        //return to the PAS of matH
    matC6  = myNmrTmp.mult(matRt, matC5);       //return to the PAS of matH
    matHH  = myNmrTmp.matriceHamilton(matHD, tp2);
    matHHC = myNmrTmp.matConjugue(matHH);
    matC7  = myNmrTmp.mult(matC6, matHH);       //action of the second +x pulse
    matC8  = myNmrTmp.mult(matHHC, matC7);      //action of the second +x pulse
    matC9  = myNmrTmp.mult(matC8, matRt);       //back to the
    matC10 = myNmrTmp.mult(matR, matC9);        //rotating frame

    amplitudeImag[i] = (pop/coeff)*matC10.im[ligneST][ligneST - 1];
    amplitudeReal[i] = (pop/coeff)*matC10.re[ligneST][ligneST - 1];

    if (checkboxReal.getState()) {
      for (int ii = 0; ii < nbou + 1; ii++) amplitude[ii] = amplitudeReal[ii];
    }
    else {
      for (int ii = 0; ii < nbou + 1; ii++) amplitude[ii] = amplitudeImag[ii];
    }
  }//end of solomonEkoSequence()

  private void calculIntensite(double omegaQTmp, double omegaRFTmp) {
    RealMat  matH, matHD, matR, matRt, matIz, matR1, matR2;
    double   tp;

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

    for (int i = 0; i < nbou + 1; i++) {
      amplitudeReal[i] = 0.0;
      amplitudeImag[i] = 0.0;
    }//clear

    //first x pulse
    matH  = myNmr.dataIn();          //find eigenvectors and eigenvalues of matH
    matHD = myNmr.jacRot(matH);       //matHD is the eigenvalue matrix of matH
    matR  = myNmr.getMatR();          //matR is the eigenvector matrix of matH
    matRt = RealMat.transpose(matR);  //matRt is the transposed matrix of matR
    matIz = myNmr.matriceIz();        //matrix of spin operator Iz
    matR1 = myNmr.mult(matIz, matR);  //matrix of Iz expressed in the PAS
    matR2 = myNmr.mult(matRt, matR1); //of matH

    switch (choiceSequence.getSelectedIndex()) {
      case 0:  //A(p1)B()
        for (int i = 0; i <= nbou; i++) {
          tp = dureePremiere + i*dureePas;
          solomonEkoSequence(i, myNmr, tp, dureePremiere2,
                             matHD, matR, matRt, matR2);
        }
        break;
      case 1:  //A()B(p2)
        for (int i = 0; i <= nbou; i++) {
          tp = dureePremiere + i*dureePas;
          solomonEkoSequence(i, myNmr, dureePremiere1, tp,
                             matHD, matR, matRt, matR2);
        }
        break;
    }//end of switch
  }//end of calculIntensite()

  private void afficheTransition() {
    choiceTransition.removeAll();  //clear
    choiceEkoPosition.removeAll(); //clear
    switch (choiceSpin.getSelectedIndex()) {
      case 0: //spin 3/2
              choiceTransition.add("Satellite Transitions");
              choiceEkoPosition.add("tau2");
              break;
      case 1: //spin 5/2
              choiceTransition.add("Inner Satellite Transitions");
              choiceTransition.add("Outer Satellite Transitions");
              choiceEkoPosition.add("tau2");
              choiceEkoPosition.add("2*tau2");
              choiceEkoPosition.add("3*tau2");
              break;
      case 2: //spin 7/2
              choiceTransition.add("Inner Satellite Transitions");
              choiceTransition.add("Medium Satellite Transitions");
              choiceTransition.add("Outer Satellite Transitions");
              choiceEkoPosition.add("tau2");
              choiceEkoPosition.add("2*tau2");
              choiceEkoPosition.add("3*tau2-1Q");
              choiceEkoPosition.add("3*tau2-nQ");
              choiceEkoPosition.add("5*tau2");
              choiceEkoPosition.add("6*tau2");
              break;
      case 3: //spin 9/2
              choiceTransition.add("Inner Satellite Transitions");
              choiceTransition.add("Medium Satellite Transitions");
              choiceTransition.add("Next Satellite Transitions");
              choiceTransition.add("Outer Satellite Transitions");
              choiceEkoPosition.add("tau2");
              choiceEkoPosition.add("2*tau2");
              choiceEkoPosition.add("3*tau2-1Q");
              choiceEkoPosition.add("3*tau2-nQ");
              choiceEkoPosition.add("4*tau2");
              choiceEkoPosition.add("5*tau2");
              choiceEkoPosition.add("6*tau2");
              choiceEkoPosition.add("7*tau2");
              choiceEkoPosition.add("9*tau2");
              choiceEkoPosition.add("10*tau2");
              break;
      }//end of switch
    choiceTransition.select(0);
    choiceEkoPosition.select(0);
  }//end of afficheTransition()

  private void eko3sur2() {
    ligne = 0;
    colonne = 1;
  }

  private void eko5sur2() {
    switch (choiceEkoPosition.getSelectedIndex()) {
      case 0: ligne = 1;   colonne = 2;    break;
      case 1: ligne = 0;   colonne = 1;    break;
      case 2: ligne = 0;   colonne = 2;    break;
    }
  }

  private void eko7sur2() {
    switch (choiceEkoPosition.getSelectedIndex()) {
      case 0: ligne = 2;   colonne = 3;    break;
      case 1: ligne = 1;   colonne = 2;    break;
      case 2: ligne = 0;   colonne = 1;    break;
      case 3: ligne = 1;   colonne = 3;    break;
      case 4: ligne = 0;   colonne = 2;    break;
      case 5: ligne = 0;   colonne = 3;    break;
    }
  }

  private void eko9sur2() {
    switch (choiceEkoPosition.getSelectedIndex()) {
      case 0: ligne = 3;   colonne = 4;    break;
      case 1: ligne = 2;   colonne = 3;    break;
      case 2: ligne = 1;   colonne = 2;    break;
      case 3: ligne = 2;   colonne = 4;    break;
      case 4: ligne = 0;   colonne = 1;    break;
      case 5: ligne = 1;   colonne = 3;    break;
      case 6: ligne = 1;   colonne = 4;    break;
      case 7: ligne = 0;   colonne = 2;    break;
      case 8: ligne = 0;   colonne = 3;    break;
      case 9: ligne = 0;   colonne = 4;    break;
    }
  }

  private void normalisationSignal() {
    switch (choiceSpin.getSelectedIndex()) {
      case 0: //spin 3/2
              ComplexMat.setTailleMatrice (4);
              coeff = 5.0;
              ligneST = 1;
              pop = 2*Math.sqrt(3);
              eko3sur2();
              break;
      case 1: //spin 5/2
              ComplexMat.setTailleMatrice (6);
              coeff = 35.0/2.0;
              switch (choiceTransition.getSelectedIndex()) {
                case 0: ligneST = 2;  pop = 2*Math.sqrt(8);   break;//is
                case 1: ligneST = 1;  pop = 2*Math.sqrt(5);   break;//os
              }
              eko5sur2();
              break;
      case 2: //spin 7/2
              ComplexMat.setTailleMatrice (8);
              coeff = 42.0;
              switch (choiceTransition.getSelectedIndex()) {
                case 0: ligneST = 3;  pop = 2*Math.sqrt(15);  break;//is
                case 1: ligneST = 2;  pop = 2*Math.sqrt(12);  break;//ms
                case 2: ligneST = 1;  pop = 2*Math.sqrt(7);   break;//os
              }
              eko7sur2();
              break;
      case 3: //spin 9/2
              ComplexMat.setTailleMatrice (10);
              coeff = 165.0/2.0;
              switch (choiceTransition.getSelectedIndex()) {
                case 0: ligneST = 4;  pop = 2*Math.sqrt(24);  break;//is
                case 1: ligneST = 3;  pop = 2*Math.sqrt(21);  break;//ms
                case 2: ligneST = 2;  pop = 2*Math.sqrt(16);  break;//nm
                case 3: ligneST = 1;  pop = 2*Math.sqrt(9);   break;//os
              }
              eko9sur2();
              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:  //A(p1)B(), V-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();
            break;
          case 1:  //A()B(p2), F-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;
        }//end of switch
        nbou =             (int)((dureeFin - dureePremiere)/dureePas);
        amplitude =        new double[nbou + 1];
        amplitudeReal =    new double[nbou + 1];
        amplitudeImag =    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
        afficheValeur();
        panelFit.setVisible(true);
        panelFitEstim.setVisible(true);
        panelCheckgroup.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(SolomonEkoXtalJDK118.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);
        //***panelTransition and panelFit widths + 100
        panelTransition.setLocation(260, 0);
        panelTransition.setVisible(true);
        panelFit.setLocation(480, 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);
        }
      }
    });

   //************
   //checkboxReal
   //************
    checkboxReal.addItemListener(new java.awt.event.ItemListener() {
      public void itemStateChanged(ItemEvent e) {
        for (int i = 0; i < nbou + 1; i++) amplitude[i] = amplitudeReal[i];
        afficheValeur();
      }
    });

   //************
   //checkboxImag
   //************
    checkboxImag.addItemListener(new java.awt.event.ItemListener() {
      public void itemStateChanged(ItemEvent e) {
        for (int i = 0; i < nbou + 1; i++) amplitude[i] = amplitudeImag[i];
        afficheValeur();
      }
    });

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

  //**************
  //choiceSequence
  //**************
    choiceSequence.addItemListener(new java.awt.event.ItemListener() {
      public void itemStateChanged(ItemEvent e) {
        switch (choiceSequence.getSelectedIndex()) {
          //A(p1)B(), V-F
          case 0: textFieldPremiereDuree.setVisible(true);
                  textFieldDerniereDuree.setVisible(true);
                  textFieldPas.setVisible(true);
                  textFieldPremiereDuree2.setVisible(true);
                  textFieldDerniereDuree2.setVisible(false);
                  textFieldPas2.setVisible(false);
                  break;
          //A()B(p2), F-V
          case 1: textFieldPremiereDuree.setVisible(true);
                  textFieldDerniereDuree.setVisible(false);
                  textFieldPas.setVisible(false);
                  textFieldPremiereDuree2.setVisible(true);
                  textFieldDerniereDuree2.setVisible(true);
                  textFieldPas2.setVisible(true);
                  break;
        }
      }
    });

   //*********************
   //choicePulseSequence
   //*********************
    choicePulseSequence.addItemListener(new java.awt.event.ItemListener() {
      public void itemStateChanged(ItemEvent e) {
        textAreaIntensite.setText("");  //clear
        textAreaDuree.setText("");      //clear
        panelCheckgroup.setVisible(false);
      }
    });

  //****************
  //choiceTransition
  //****************
    choiceTransition.addItemListener(new java.awt.event.ItemListener() {
      public void itemStateChanged(ItemEvent e) {
        choiceEkoPosition.removeAll();
        switch (choiceSpin.getSelectedIndex()) {
          case 0: //spin 3/2
                  choiceEkoPosition.add("tau2");
                  break;
          case 1: //spin 5/2
                  switch (choiceTransition.getSelectedIndex()) {
                    case 0: //inner satellite
                            choiceEkoPosition.add("tau2");
                            choiceEkoPosition.add("2*tau2");
                            choiceEkoPosition.add("3*tau2");
                            choiceEkoPosition.select(0);
                            break;
                    case 1: //outer satellite
                            choiceEkoPosition.add("tau2/2");
                            choiceEkoPosition.add("tau2");
                            choiceEkoPosition.add("3*tau2/2");
                            choiceEkoPosition.select(1);
                            break;
                  }
                  break;
          case 2: //spin 7/2
                  switch (choiceTransition.getSelectedIndex()) {
                    case 0: //inner satellite
                            choiceEkoPosition.add("tau2");
                            choiceEkoPosition.add("2*tau2");
                            choiceEkoPosition.add("3*tau2-1Q");
                            choiceEkoPosition.add("3*tau2-nQ");
                            choiceEkoPosition.add("5*tau2");
                            choiceEkoPosition.add("6*tau2");
                            choiceEkoPosition.select(0);
                            break;
                    case 1: //medium satellite
                            choiceEkoPosition.add("tau2/2");
                            choiceEkoPosition.add("tau2");
                            choiceEkoPosition.add("3*tau2/2-1Q");
                            choiceEkoPosition.add("3*tau2/2-nQ");
                            choiceEkoPosition.add("5*tau2/2");
                            choiceEkoPosition.add("3*tau2");
                            choiceEkoPosition.select(1);
                            break;
                    case 2: //outer satellite
                            choiceEkoPosition.add("tau2/3");
                            choiceEkoPosition.add("2*tau2/3");
                            choiceEkoPosition.add("tau2-1Q");
                            choiceEkoPosition.add("tau2-nQ");
                            choiceEkoPosition.add("5*tau2/3");
                            choiceEkoPosition.add("2*tau2");
                            choiceEkoPosition.select(2);
                            break;
                  }
                  break;
          case 3: //spin 9/2
                  switch (choiceTransition.getSelectedIndex()) {
                    case 0: //inner satellite
                            choiceEkoPosition.add("tau2");
                            choiceEkoPosition.add("2*tau2");
                            choiceEkoPosition.add("3*tau2-1Q");
                            choiceEkoPosition.add("3*tau2-nQ");
                            choiceEkoPosition.add("4*tau2");
                            choiceEkoPosition.add("5*tau2");
                            choiceEkoPosition.add("6*tau2");
                            choiceEkoPosition.add("7*tau2");
                            choiceEkoPosition.add("9*tau2");
                            choiceEkoPosition.add("10*tau2");
                            choiceEkoPosition.select(0);
                            break;
                    case 1: //medium satellite
                            choiceEkoPosition.add("tau2/2");
                            choiceEkoPosition.add("tau2");
                            choiceEkoPosition.add("3*tau2/2-1Q");
                            choiceEkoPosition.add("3*tau2/2-nQ");
                            choiceEkoPosition.add("2*tau2");
                            choiceEkoPosition.add("5*tau2/2");
                            choiceEkoPosition.add("3*tau2");
                            choiceEkoPosition.add("7*tau2/2");
                            choiceEkoPosition.add("9*tau2/2");
                            choiceEkoPosition.add("5*tau2");
                            choiceEkoPosition.select(1);
                            break;
                    case 2: //next medium satellite
                            choiceEkoPosition.add("tau2/3");
                            choiceEkoPosition.add("2*tau2/3");
                            choiceEkoPosition.add("tau2-1Q");
                            choiceEkoPosition.add("tau2-nQ");
                            choiceEkoPosition.add("4*tau2/3");
                            choiceEkoPosition.add("5*tau2/3");
                            choiceEkoPosition.add("2*tau2");
                            choiceEkoPosition.add("7*tau2/3");
                            choiceEkoPosition.add("3*tau2");
                            choiceEkoPosition.add("10*tau2/3");
                            choiceEkoPosition.select(2);
                            break;
                    case 3: //outer satellite
                            choiceEkoPosition.add("tau2/4");
                            choiceEkoPosition.add("tau2/2");
                            choiceEkoPosition.add("3*tau2/4-1Q");
                            choiceEkoPosition.add("3*tau2/4-nQ");
                            choiceEkoPosition.add("tau2");
                            choiceEkoPosition.add("5*tau2/4");
                            choiceEkoPosition.add("3*tau2/2");
                            choiceEkoPosition.add("7*tau2/4");
                            choiceEkoPosition.add("9*tau2/4");
                            choiceEkoPosition.add("5*tau2/2");
                            choiceEkoPosition.select(4);
                            break;
                  }
                  break;
        }
      }
    });
  }//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 afficheValeur() {
    //show the echo amplitude versus the pulse length
    double tp = 0;
    String s = "", s2 = "";
    textAreaIntensite.setText("");  //clear
    textAreaDuree.setText("");      //clear
    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 afficheValeur()

  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 verus the
    //pulse length
    String st1 = "p1 (" + (char) 181 + "s)",
           st2 = "p2 (" + (char) 181 + "s)";
    switch (choiceSequence.getSelectedIndex()) {
      case 0: Graph("Solomon echo to crystal", st1, "A(p1)B()"); break;
      case 1: Graph("Solomon echo to crystal", st2, "A()B(p2)"); break;
    }
    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]);
    }
    repaint();
  }//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(1000);}
        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 SolomonEkoXtalJDK118