package ppmrmn;

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

public class MQMASPowderJDK118 extends Graph implements Runnable, Population {

  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,
                  ligneCT = 2,
                  nbBarre = 25; //nomber of columns of the powder pattern
  private char    choix = '3';  //P-Quantum coherence generated by the first pulse
  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,
                  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
                  population[] = new int[nbBarre];  //for powder pattern

  //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 panelSpinUnit =   new Panel();

  //panelTransition includes panelSimulation and scrollPaneSimulation

  Panel panelSimulation = new Panel();    Panel panelTransition = 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 choiceEkoAntieko = new Choice();
  Choice choiceSpin =       new Choice();
  Choice choiceSequence =   new Choice();
  Choice choiceEta =        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-04");
  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 coherence");
  Label labelExperimental = new Label("Experimental");
  Label labelExpIntensite = new Label("Intensity");
  Label labelAdvice =       new Label("Deactivate graph speeds up fitting!!!");

  TextField textFieldOmegaQ =         new TextField("250.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("5.0");

  TextField textFieldOmegaQEst =      new TextField("200");
  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 MQMASPowderJDK118() {
  }

  /**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, 60, 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));

    choiceEkoAntieko.add("Echo");
    choiceEkoAntieko.add("Anti-Echo");

    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.add("B(p2)");
    choiceSequence.add("A(p1)");

    choiceEta.add("0.0");    choiceEta.add("0.1");    choiceEta.add("0.2");
    choiceEta.add("0.3");    choiceEta.add("0.4");    choiceEta.add("0.5");
    choiceEta.add("0.6");    choiceEta.add("0.7");    choiceEta.add("0.8");
    choiceEta.add("0.9");    choiceEta.add("1.0");
    population = POPULATION_ETA00;

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

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

    panelSpinLabel.add(choiceEkoAntieko);
    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(" QCC"));
    panelSpinData.add(textFieldOmegaQ);
    panelSpinData2.add(new Label("  kHz"));
    panelSpinUnit.add(new Label(""));

    panelSpinLabel.add(new Label(" Eta"));
    panelSpinData.add(choiceEta);
    panelSpinData2.add(new Label(""));
    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"));

    textFieldDerniereDuree2.setVisible(false);
    textFieldPas2.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(60, 305, 85, hautLB);
    panelTransition.add(labelOf);

    choiceTransition.add("1Q");
    choiceTransition.add("-3Q");
    choiceTransition.select(1);
    choix = '3';
    choiceTransition.setBounds(10, 325, 180, 30);
    panelTransition.add(choiceTransition);

    textAreaDuree.setEditable(false);
    textAreaIntensite.setEditable(false);

    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("QCC:"));
    panelFitEstim.add(new Label(""));
    panelFitEstim.add(textFieldOmegaQEst);
    panelFitEstim.add(new Label("  kHz"));

    //valeurs exemples
    String s5 = 0+"\n"+0+"\n"+0+"\n"+5+"\n"+23+"\n"+66+"\n"+152+"\n"+299+"\n";
    s5 += 522+"\n"+829+"\n"+1225+"\n"+1700+"\n"+2243+"\n"+2834+"\n";
    s5 += 3455+"\n"+4086+"\n"+4713+"\n"+5323+"\n"+5908+"\n"+6462+"\n"+6975+"\n";
    textAreaExpIntensite.setText(s5);
  }//end of jbInit()

  private void mqSequence(int i, int k, 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;

    //the 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

    double z1 = matC4.im[ligne][colonne];
    matCz  = myNmrTmp.matSingle(matC4, ligne, colonne);

    switch (choiceSequence.getSelectedIndex()) {
      case 3:  //A(p1)
        amplitude[i] += (pop/coeff)*population[population.length - k -1]*z1;
        break;
      default:
        //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

        switch (choiceSequence.getSelectedIndex()) {
          case 0:  //A(p1)B()
            amplitude[i] += (pop/coeff)*population[population.length - k -1]
                            *matC10.im[ligneCT][ligneCT - 1];
            break;
          case 1:  //A()B(p2)
            amplitude[i] += (pop/coeff)*population[population.length - k -1]
                            *matC10.im[ligneCT][ligneCT - 1];
            break;
          case 2:  //B(p2)
            amplitude[i] += -(pop/coeff)*population[population.length - k -1]
                            *(matC10.im[ligneCT][ligneCT - 1])/z1;
            break;
        }
        break;
    }
  }//end of mqSequence()

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

    //omegaQ <-> QCC, and omegaRF in kHz unit
    Nmr myNmr = new Nmr(omegaQTmp, omegaRFTmp);
    //OmegaQ <-> QCC, and omegaRF in radian/second unit

    double  tp =     0,
            deltaY = 2.0/nbBarre,      //width of a column in the powder pattern
            spin1 =  myNmr.getSpin(),               //get the spin value
            rap =    3.0/(8*spin1*(2*spin1 - 1)),   //factor associated with QCC
            tmp1 =   myNmr.getOmegaQ();             //QCC in radian/second unit

    for (int i = 0; i <= nbou; i++) amplitude[i] = 0.0;  //clear

    //k < population
    for (int k = 0 ; k < population.length; k++) {
      double tmp2 = k*tmp1*deltaY*rap;
      myNmr.setOmegaQ(tmp2);
      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 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;
            mqSequence(i, k, myNmr, tp, dureePremiere2,
                       matHD, matR, matRt, matR2);
          }
          break;
        case 1:  //A()B(p2)
          for (int i = 0; i <= nbou; i++) {
            tp = dureePremiere + i*dureePas;
            mqSequence(i, k, myNmr, dureePremiere1, tp,
                       matHD, matR, matRt, matR2);
          }
          break;
        case 2:  //B(p2)
          for (int i = 0; i <= nbou; i++) {
            tp = dureePremiere + i*dureePas;
            mqSequence(i, k, myNmr, dureePremiere1, tp,
                       matHD, matR, matRt, matR2);
          }
          break;
        case 3:  //A(p1)
          for (int i = 0; i <= nbou; i++) {
            tp = dureePremiere + i*dureePas;
            mqSequence(i, k, myNmr, tp, dureePremiere2,
                       matHD, matR, matRt, matR2);
          }
          break;
      }//end of switch
    }//end of for k
  }//end of calculIntensite()

  private void afficheTransition() {
    choiceTransition.removeAll();
    switch (choiceEkoAntieko.getSelectedIndex()) {
      //echo
      case 0: switch (choiceSpin.getSelectedIndex()) {
                case 0: //spin 3/2
                        choiceTransition.add("1Q");
                        choiceTransition.add("-3Q");
                        break;
                case 1: //spin 5/2
                        choiceTransition.add("1Q");
                        choiceTransition.add("3Q");
                        choiceTransition.add("-5Q");
                        break;
                case 2: //spin 7/2
                        choiceTransition.add("1Q");
                        choiceTransition.add("3Q");
                        choiceTransition.add("5Q");
                        choiceTransition.add("-7Q");
                        break;
                case 3: //spin 9/2
                        choiceTransition.add("1Q");
                        choiceTransition.add("3Q");
                        choiceTransition.add("5Q");
                        choiceTransition.add("7Q");
                        choiceTransition.add("-9Q");
                        break;
              }//end of case 0
              break;
      //antiecho
      case 1: switch (choiceSpin.getSelectedIndex()) {
                case 0: //spin 3/2
                        choiceTransition.add("-1Q");
                        choiceTransition.add("3Q");
                        break;
                case 1: //spin 5/2
                        choiceTransition.add("-1Q");
                        choiceTransition.add("-3Q");
                        choiceTransition.add("5Q");
                        break;
                case 2: //spin 7/2
                        choiceTransition.add("-1Q");
                        choiceTransition.add("-3Q");
                        choiceTransition.add("-5Q");
                        choiceTransition.add("7Q");
                        break;
                case 3: //spin 9/2
                        choiceTransition.add("-1Q");
                        choiceTransition.add("-3Q");
                        choiceTransition.add("-5Q");
                        choiceTransition.add("-7Q");
                        choiceTransition.add("9Q");
                        break;
              }//end of case 1
              break;
      }//end of switch
    choiceTransition.select(1);
    choix ='3';
  }//end of afficheTransition()

  private void normalisationSignal() {
    switch (choiceEkoAntieko.getSelectedIndex()) {
      // echo
      case 0: switch (choiceSpin.getSelectedIndex()) {
                case 0: ComplexMat.setTailleMatrice(4);
                        ligneCT = 2;  coeff = 5.0;  pop = Math.sqrt(4);
                         switch (choix) {
                           case '1': ligne = 1;   colonne = 2;  break;
                           case '3': ligne = 3;   colonne = 0;  break;
                         }
                         break;
                 case 1: ComplexMat.setTailleMatrice(6);
                         ligneCT = 3;  coeff = 35.0/2.0;  pop = Math.sqrt(9);
                         switch (choix) {
                           case '1': ligne = 2;   colonne = 3;  break;
                           case '3': ligne = 1;   colonne = 4;  break;
                           case '5': ligne = 5;   colonne = 0;  break;
                         }
                         break;
                 case 2: ComplexMat.setTailleMatrice(8);
                         ligneCT = 4;  coeff = 42.0;  pop = Math.sqrt(16);
                         switch (choix) {
                           case '1': ligne = 3;   colonne = 4;  break;
                           case '3': ligne = 2;   colonne = 5;  break;
                           case '5': ligne = 1;   colonne = 6;  break;
                           case '7': ligne = 7;   colonne = 0;  break;
                         }
                         break;
                 case 3: ComplexMat.setTailleMatrice(10);
                         ligneCT = 5;  coeff = 165.0/2.0;  pop = Math.sqrt(25);
                         switch (choix) {
                           case '1': ligne = 4;   colonne = 5;  break;
                           case '3': ligne = 3;   colonne = 6;  break;
                           case '5': ligne = 2;   colonne = 7;  break;
                           case '7': ligne = 1;   colonne = 8;  break;
                           case '9': ligne = 9;   colonne = 0;  break;
                         }
                         break;
              }  //end of switch case 0
              break;
      // antiécho
      case 1: switch (choiceSpin.getSelectedIndex()) {
                case 0: ComplexMat.setTailleMatrice(4);
                        ligneCT = 2;  coeff = 5.0;  pop = Math.sqrt(4);
                        switch (choix) {
                          case '1': ligne = 2;   colonne = 1;  break;
                          case '3': ligne = 0;   colonne = 3;  break;
                        }
                        break;
                case 1: ComplexMat.setTailleMatrice(6);
                        ligneCT = 3;  coeff = 35.0/2.0;  pop = Math.sqrt(9);
                        switch (choix) {
                          case '1': ligne = 3;   colonne = 2;  break;
                          case '3': ligne = 4;   colonne = 1;  break;
                          case '5': ligne = 0;   colonne = 5;  break;
                        }
                        break;
                case 2: ComplexMat.setTailleMatrice(8);
                        ligneCT = 4;  coeff = 42.0;  pop = Math.sqrt(16);
                        switch (choix) {
                          case '1': ligne = 4;   colonne = 3;  break;
                          case '3': ligne = 5;   colonne = 2;  break;
                          case '5': ligne = 6;   colonne = 1;  break;
                          case '7': ligne = 0;   colonne = 7;  break;
                        }
                        break;
                case 3: ComplexMat.setTailleMatrice(10);
                        ligneCT = 5;  coeff = 165.0/2.0;  pop = Math.sqrt(25);
                        switch (choix) {
                          case '1': ligne = 5;   colonne = 4;  break;
                          case '3': ligne = 6;   colonne = 3;  break;
                          case '5': ligne = 7;   colonne = 2;  break;
                          case '7': ligne = 8;   colonne = 1;  break;
                          case '9': ligne = 0;   colonne = 9;  break;
                        }
                        break;
              }//end of switch case 1
              break;
    }//end of switch choiceEkoAntieko
  }//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;
          case 2:  //B(p2), I-V
          dureePremiere1 =
          1.0/(2*pop*Double.valueOf(textFieldOmegaRF.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 3:  //A(p1), V-I
          dureeFin =
          milli*Double.valueOf(textFieldDerniereDuree.getText()).doubleValue();
          dureePremiere =
          milli*Double.valueOf(textFieldPremiereDuree.getText()).doubleValue();
          dureePas =
          milli*Double.valueOf(textFieldPas.getText()).doubleValue();
          dureePremiere2 =
          1.0/(2*pop*Double.valueOf(textFieldOmegaRF.getText()).doubleValue());
            break;
        }//end of switch
        nbou =             (int)((dureeFin - dureePremiere)/dureePas);
        amplitude =        new double[nbou + 1];        //FID intensity
        listExpIntensity = new double[nbou + 1];        //experimental intensity
        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() + (int)(amplitude[i]) + "\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(MQMASPowderJDK118.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 + 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);
        }
      }
    });

  //**********
  //choiceEta
  //**********
    choiceEta.addItemListener(new java.awt.event.ItemListener() {
      public void itemStateChanged(ItemEvent e) {
        switch (choiceEta.getSelectedIndex()) {
          case 0: population = POPULATION_ETA00;  break;
          case 1: population = POPULATION_ETA01;  break;
          case 2: population = POPULATION_ETA02;  break;
          case 3: population = POPULATION_ETA03;  break;
          case 4: population = POPULATION_ETA04;  break;
          case 5: population = POPULATION_ETA05;  break;
          case 6: population = POPULATION_ETA06;  break;
          case 7: population = POPULATION_ETA07;  break;
          case 8: population = POPULATION_ETA08;  break;
          case 9: population = POPULATION_ETA09;  break;
          case 10: population = POPULATION_ETA10; break;
        }//end of switch
      }
    });

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

  //****************
  //choiceEkoAntieko
  //****************
    choiceEkoAntieko.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()) {
          //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;
          //B(p2), I-V
          case 2: textFieldPremiereDuree.setVisible(false);
                  textFieldDerniereDuree.setVisible(false);
                  textFieldPas.setVisible(false);
                  textFieldPremiereDuree2.setVisible(true);
                  textFieldDerniereDuree2.setVisible(true);
                  textFieldPas2.setVisible(true);
                  break;
          //A(p1), V-I
          case 3: textFieldPremiereDuree.setVisible(true);
                  textFieldDerniereDuree.setVisible(true);
                  textFieldPas.setVisible(true);
                  textFieldPremiereDuree2.setVisible(false);
                  textFieldDerniereDuree2.setVisible(false);
                  textFieldPas2.setVisible(false);
                  break;
        }
      }
    });

  //****************
  //choiceTransition
  //****************
    choiceTransition.addItemListener(new java.awt.event.ItemListener() {
      public void itemStateChanged(ItemEvent e) {
        String rangTransition = choiceTransition.getSelectedItem();
        if (rangTransition == "-1Q") choix = '1';
          else if (rangTransition == "1Q") choix = '1';
            else if (rangTransition == "3Q") choix = '3';
              else if (rangTransition == "-3Q") choix = '3';
                else if (rangTransition == "5Q") choix = '5';
                  else if (rangTransition == "-5Q") choix = '5';
                    else if (rangTransition == "7Q") choix = '7';
                      else if (rangTransition == "-7Q") choix = '7';
                        else if (rangTransition == "9Q") choix = '9';
                          else if (rangTransition == "-9Q") choix = '9';
        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 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
    double inc;
    switch (choiceSequence.getSelectedIndex()) {
      case 0: Graph("2-pulse MQMAS to powder", "p1 (µs)", "A(p1)B()"); break;
      case 1: Graph("2-pulse MQMAS to powder", "p2 (µs)", "A()B(p2)"); break;
      case 2: Graph("2-pulse MQMAS to powder", "p2 (µs)", "B(p2)");    break;
      case 3: Graph("2-pulse MQMAS to powder", "p1 (µs)", "A(p1)");    break;
    }
    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("QCC: " + 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 MQMASPowderJDK118