package ppmrmn;       import java.awt.*;       import java.applet.*;
//28 septembre 2001

public class SolomonEkoXtal extends Applet implements Runnable{

  Thread th = null;  //pour exécuter la méthode simplex dans run() et visualiser les courbes

  //les 4 constantes utilisées par la méthode simplex()
  static final int REFLECTFACT = 1;           static final int EXPANDFACT = 2;
  static final double CONTRACTFACT = 0.5;     static final int MAXITER = 1000;

  int     numVars = 3,  //nombre de variables à ajuster par la méthode simplex()
          cent    = 10, //position du graph utilisé dans graph()
          ligne = 1,            colonne = 2,            ligneST = 1,
          nbou = 1,        //nombre de durées d'impulsion + 1
          hautPanel = 390; //hauteur des Panels
  double  coeff = 5,            pop = 2*Math.sqrt(3),
          dureeFin = 1,         dureePremiere = 0,      dureePas = 1,
          dureePremiere1 = 0,   dureePremiere2 = 0,
          amplitude[] = {0.0},        //intensité du FID
          amplitudeReal[] = {0.0},   amplitudeImag[] = {0.0},
          listExpIntensity[] = {0.0}, //intensité expérimentale
          //matEstimation[][] est la matrice des valeurs estimées initiales
          matEstimation[][] = new double[numVars + 1][numVars];
  boolean stopFit = false,      showCurve = true;
  //°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
  //Dimension de l'applet 700LX390H à préciser dans la source de l'applet (page WEB)
  //°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°

  //PanelSpin contient panelSpinLabel, panelSpinData, panelSpinData2 et panelSpinUnit
  Panel panelSpin =       new Panel();          Panel panelSpinLabel = new Panel();
  Panel panelSpinData =   new Panel();          Panel panelSpinData2 = new Panel();
  Panel panelSpinUnit =   new Panel();

  //PanelTransition contient panelBlanc et panelCheckgroup
  Panel panelTransition = new Panel();          Panel panelBlanc =     new Panel();
  Panel panelCheckgroup = new Panel();

  //PanelFit contient panelFitAlpha, panelFitEstim, panelFitBouton, panelFitOmegaRF et panelFitQCC
  Panel panelFit =        new Panel();          Panel panelFitEstim =  new Panel();
  Panel panelFitBouton =  new Panel();          Panel panelFitAlpha =  new Panel();
  Panel panelFitOmegaRF = new Panel();          Panel panelFitQCC =    new Panel();

  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);

  Choice choiceSpin =           new Choice();   Choice choiceAlpha =          new Choice();
  Choice choiceSequence =       new Choice();   Choice choicePulseSequence =  new Choice();
  Choice choiceTransition =     new Choice();
  Choice choiceTransition3 =    new Choice();   Choice choiceTransition5 =    new Choice();
  Choice choiceTransition7 =    new Choice();   Choice choiceTransition9 =    new Choice();
  Choice choiceEkoPosition =    new Choice();   Choice choiceEkoPosition3 =   new Choice();
  Choice choiceEkoPosition5is = new Choice();   Choice choiceEkoPosition5os = new Choice();
  Choice choiceEkoPosition7is = new Choice();   Choice choiceEkoPosition7ms = new Choice();
  Choice choiceEkoPosition7os = new Choice();
  Choice choiceEkoPosition9is = new Choice();   Choice choiceEkoPosition9ms = new Choice();
  Choice choiceEkoPosition9nm = new Choice();   Choice choiceEkoPosition9os = new Choice();

  Label labelDate =         new Label("28-09-01");
  Label labelDuree =        new Label("Length (µs)");    //durée de l'impulsion
  Label labelIntensite =    new Label("Intensity");      //intensité du signal
  Label labelTransition =   new Label("Nature of the echo:");
  Label labelPosition =     new Label("Position of the echo:");
  Label labelExpIntensite = new Label("Exp. Intensity"); //intensité exp. du signal
  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");

  TextArea textAreaDuree =            new TextArea(12,7);  //durée
  TextArea textAreaIntensite =        new TextArea(12,7);  //intensité partie imaginaire
  TextArea textAreaIntensiteReel =    new TextArea(12,7);  //intensité parite réelle
  TextArea textAreaExpIntensite =     new TextArea(12,7);  //Exp intensité
  TextArea textAreaParameter =        new TextArea(5,7);   //Exp fit

  /**Construct the applet*/
  public SolomonEkoXtal() {
  }
  /**Initialize the applet*/
  public void init() {
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
  /**Component initialization*/
  private void jbInit() throws Exception {
    int hautLB = 20,      //hauteur du label
        hautBouton = 30,  //hauteur des boutons
        haut = 20,     largeur = 180,      origineX = 10,      yChoiceE = 295,      yChoiceT = 245;

    setBackground(Color.white);  setLayout(null);
    buttonGraph.move(75, 355);   buttonGraph.resize(150, hautBouton);    add(buttonGraph);
    buttonGraph.hide();
    labelAdvice.move(15, 320);   labelAdvice.resize(220, hautBouton);    add(labelAdvice);
    labelAdvice.setFont(new Font("TimesRoman", Font.PLAIN, 10));
    labelAdvice.setBackground(Color.pink);  //sauf IE5.5, les autres navigateurs créent une zone
    labelAdvice.hide();
    //***modifie panelSpin largeur + 100
    panelSpin.move(0, 0);        panelSpin.resize(260, hautPanel);       add(panelSpin);
    panelSpinLabel.move(0, 0);   panelSpinLabel.resize(90, hautPanel-3); panelSpin.add(panelSpinLabel);
    panelSpinData.move(90, 0);   panelSpinData.resize(60, hautPanel-3);  panelSpin.add(panelSpinData);
    panelSpinData2.move(150, 0); panelSpinData2.resize(60, hautPanel-3); panelSpin.add(panelSpinData2);
    panelSpinUnit.move(210, 0);  panelSpinUnit.resize(50, hautPanel-3);  panelSpin.add(panelSpinUnit);
    //***modifie panelTransition + 100
    panelTransition.move(260, 0);   panelTransition.resize(220, hautPanel);   add(panelTransition);
    //***modifie panelFit + 100
    panelFit.move(480, 0);       panelFit.resize(220, hautPanel);        add(panelFit);
    panelFit.hide();

//******************************************************************************
//                                  panelSpin
//******************************************************************************
    panelSpin.setBackground(Color.pink);             panelSpin.setLayout(null);
    panelSpin.setFont(new Font("TimesRoman", Font.PLAIN, 12));

    panelSpinLabel.setLayout(new GridLayout(8, 1, 0, 10)); //8 lignes, 1 colonne
    panelSpinData.setLayout(new GridLayout(8, 1, 0, 10));  //0 espace horizontale
    panelSpinData2.setLayout(new GridLayout(8, 1, 0, 10)); //10 espaces verticales
    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"));

    choicePulseSequence.addItem("X-X");              choicePulseSequence.addItem("Y-X");
    choicePulseSequence.select(0);  //initialisation

    choiceSpin.addItem("3/2");                       choiceSpin.addItem("5/2");
    choiceSpin.addItem("7/2");                       choiceSpin.addItem("9/2");
    choiceSpin.select(0);  //initialisation

    choiceSequence.addItem("A(p1)B()");              choiceSequence.addItem("A()B(p2)");
    choiceSequence.select(1);  //initialisation

    textFieldDerniereDuree.hide();                   textFieldPas.hide();

//******************************************************************************
//                                 panelTransition
//******************************************************************************
    panelTransition.setBackground(Color.pink);       panelTransition.setLayout(null);
    panelTransition.setFont(new Font("TimesRoman", Font.PLAIN, 12));

    labelDuree.move(15, 7);                          labelDuree.resize(100, hautLB);
    panelTransition.add(labelDuree);
    labelIntensite.move(125, 7);                     labelIntensite.resize(100, hautLB);
    panelTransition.add(labelIntensite);
    labelTransition.move(origineX, 220);             labelTransition.resize(180, hautLB);
    panelTransition.add(labelTransition);
    labelPosition.move(origineX, 270);               labelPosition.resize(180, hautLB);
    panelTransition.add(labelPosition);

    textAreaDuree.move(origineX, 30);                textAreaDuree.resize(80, 150);
    panelTransition.add(textAreaDuree);
    textAreaIntensite.move(110, 30);                 textAreaIntensite.resize(80, 150);
    panelTransition.add(textAreaIntensite);

    panelCheckgroup.move(110, 185);                  panelCheckgroup.resize(110, 30);
    panelTransition.add(panelCheckgroup);            panelCheckgroup.setBackground(Color.pink);
    panelCheckgroup.setLayout(new GridLayout(2, 1)); //2 lignes, 1 colonne
    panelCheckgroup.add(checkboxReal);               panelCheckgroup.add(checkboxImag);
    checkboxReal.setBackground(Color.pink);          checkboxImag.setBackground(Color.pink);

    choiceTransition3.move(origineX, yChoiceT);      choiceTransition3.resize(largeur, haut);
    choiceTransition5.move(origineX, yChoiceT);      choiceTransition5.resize(largeur, haut);
    choiceTransition7.move(origineX, yChoiceT);      choiceTransition7.resize(largeur, haut);
    choiceTransition9.move(origineX, yChoiceT);      choiceTransition9.resize(largeur, haut);

    choiceEkoPosition3.move(origineX, yChoiceE);     choiceEkoPosition3.resize(largeur, haut);
    choiceEkoPosition5is.move(origineX, yChoiceE);   choiceEkoPosition5is.resize(largeur, haut);
    choiceEkoPosition5os.move(origineX, yChoiceE);   choiceEkoPosition5os.resize(largeur, haut);
    choiceEkoPosition7is.move(origineX, yChoiceE);   choiceEkoPosition7is.resize(largeur, haut);
    choiceEkoPosition7ms.move(origineX, yChoiceE);   choiceEkoPosition7ms.resize(largeur, haut);
    choiceEkoPosition7os.move(origineX, yChoiceE);   choiceEkoPosition7os.resize(largeur, haut);
    choiceEkoPosition9is.move(origineX, yChoiceE);   choiceEkoPosition9is.resize(largeur, haut);
    choiceEkoPosition9ms.move(origineX, yChoiceE);   choiceEkoPosition9ms.resize(largeur, haut);
    choiceEkoPosition9nm.move(origineX, yChoiceE);   choiceEkoPosition9nm.resize(largeur, haut);
    choiceEkoPosition9os.move(origineX, yChoiceE);   choiceEkoPosition9os.resize(largeur, haut);

    //choiceTransition3 se trouve au-dessus au début dans applet panel parce qu'il est le premier
    //des choiceTransitions qui ont la meme position (superposés)
    panelTransition.add(choiceTransition3);
    choiceTransition3.addItem("Satellite transitions");
    choiceTransition3.select(0);      choiceTransition3.hide();

    panelTransition.add(choiceTransition5);
    choiceTransition5.addItem("Inner satellite transitions");
    choiceTransition5.addItem("Outer satellite transitions");
    choiceTransition5.select(0);      choiceTransition5.hide();  //sinon problème avec imprimante

    panelTransition.add(choiceTransition7);
    choiceTransition7.addItem("Inner satellite transitions");
    choiceTransition7.addItem("Medium satellite transitions");
    choiceTransition7.addItem("Outer satellite transitions");
    choiceTransition7.select(0);      choiceTransition7.hide();  //sinon problème avec imprimante

    panelTransition.add(choiceTransition9);
    choiceTransition9.addItem("Inner satellite transitions");
    choiceTransition9.addItem("Medium satellite transitions");
    choiceTransition9.addItem("Next medium satellite transitions");
    choiceTransition9.addItem("Outer satellite transitions");
    choiceTransition9.select(0);      choiceTransition9.hide();  //sinon problème avec imprimante

    choiceTransition = choiceTransition3;         choiceTransition.show();

    //choiceEkoPosition3 se trouve au-dessus au début dans applet panel parce qu'il est le premier
    //des choiceEkoPositions qui ont la meme position (superposés)
    panelTransition.add(choiceEkoPosition3);
    choiceEkoPosition3.addItem("tau2");
    choiceEkoPosition3.select(0);  //initialisation
    choiceEkoPosition3.hide();    //sinon problème avec imprimante

    panelTransition.add(choiceEkoPosition5is);
    choiceEkoPosition5is.addItem("tau2");         choiceEkoPosition5is.addItem("2*tau2");
    choiceEkoPosition5is.addItem("3*tau2");       choiceEkoPosition5is.select(0);  //
    choiceEkoPosition5is.hide();  //sinon problème avec imprimante

    panelTransition.add(choiceEkoPosition5os);
    choiceEkoPosition5os.addItem("tau2/2");       choiceEkoPosition5os.addItem("tau2");
    choiceEkoPosition5os.addItem("3*tau2/2");     choiceEkoPosition5os.select(1);  //
    choiceEkoPosition5os.hide();  //sinon problème avec imprimante

    panelTransition.add(choiceEkoPosition7is);
    choiceEkoPosition7is.addItem("tau2");         choiceEkoPosition7is.addItem("2*tau2");
    choiceEkoPosition7is.addItem("3*tau2-1Q");    choiceEkoPosition7is.addItem("3*tau2-nQ");
    choiceEkoPosition7is.addItem("5*tau2");       choiceEkoPosition7is.addItem("6*tau2");
    choiceEkoPosition7is.select(0);               choiceEkoPosition7is.hide();  //

    panelTransition.add(choiceEkoPosition7ms);
    choiceEkoPosition7ms.addItem("tau2/2");       choiceEkoPosition7ms.addItem("tau2");
    choiceEkoPosition7ms.addItem("3*tau2/2-1Q");  choiceEkoPosition7ms.addItem("3*tau2/2-nQ");
    choiceEkoPosition7ms.addItem("5*tau2/2");     choiceEkoPosition7ms.addItem("3*tau2");
    choiceEkoPosition7ms.select(1);               choiceEkoPosition7ms.hide();  //

    panelTransition.add(choiceEkoPosition7os);
    choiceEkoPosition7os.addItem("tau2/3");       choiceEkoPosition7os.addItem("2*tau2/3");
    choiceEkoPosition7os.addItem("tau2-1Q");      choiceEkoPosition7os.addItem("tau2-nQ");
    choiceEkoPosition7os.addItem("5*tau2/3");     choiceEkoPosition7os.addItem("2*tau2");
    choiceEkoPosition7os.select(2);               choiceEkoPosition7os.hide();  //

    panelTransition.add(choiceEkoPosition9is);
    choiceEkoPosition9is.addItem("tau2");         choiceEkoPosition9is.addItem("2*tau2");
    choiceEkoPosition9is.addItem("3*tau2-1Q");    choiceEkoPosition9is.addItem("3*tau2-nQ");
    choiceEkoPosition9is.addItem("4*tau2");       choiceEkoPosition9is.addItem("5*tau2");
    choiceEkoPosition9is.addItem("6*tau2");       choiceEkoPosition9is.addItem("7*tau2");
    choiceEkoPosition9is.addItem("9*tau2");       choiceEkoPosition9is.addItem("10*tau2");
    choiceEkoPosition9is.select(0);               choiceEkoPosition9is.hide();  //

    panelTransition.add(choiceEkoPosition9ms);
    choiceEkoPosition9ms.addItem("tau2/2");       choiceEkoPosition9ms.addItem("tau2");
    choiceEkoPosition9ms.addItem("3*tau2/2-1Q");  choiceEkoPosition9ms.addItem("3*tau2/2-nQ");
    choiceEkoPosition9ms.addItem("2*tau2");       choiceEkoPosition9ms.addItem("5*tau2/2");
    choiceEkoPosition9ms.addItem("3*tau2");       choiceEkoPosition9ms.addItem("7*tau2/2");
    choiceEkoPosition9ms.addItem("9*tau2/2");     choiceEkoPosition9ms.addItem("5*tau2");
    choiceEkoPosition9ms.select(1);               choiceEkoPosition9ms.hide();  //

    panelTransition.add(choiceEkoPosition9nm);
    choiceEkoPosition9nm.addItem("tau2/3");       choiceEkoPosition9nm.addItem("2*tau2/3");
    choiceEkoPosition9nm.addItem("tau2-1Q");      choiceEkoPosition9nm.addItem("tau2-nQ");
    choiceEkoPosition9nm.addItem("4*tau2/3");     choiceEkoPosition9nm.addItem("5*tau2/3");
    choiceEkoPosition9nm.addItem("2*tau2");       choiceEkoPosition9nm.addItem("7*tau2/3");
    choiceEkoPosition9nm.addItem("3*tau2");       choiceEkoPosition9nm.addItem("10*tau2/3");
    choiceEkoPosition9nm.select(2);               choiceEkoPosition9nm.hide();  //

    panelTransition.add(choiceEkoPosition9os);
    choiceEkoPosition9os.addItem("tau2/4");       choiceEkoPosition9os.addItem("tau2/2");
    choiceEkoPosition9os.addItem("3*tau2/4-1Q");  choiceEkoPosition9os.addItem("3*tau2/4-nQ");
    choiceEkoPosition9os.addItem("tau2");         choiceEkoPosition9os.addItem("5*tau2/4");
    choiceEkoPosition9os.addItem("3*tau2/2");     choiceEkoPosition9os.addItem("7*tau2/4");
    choiceEkoPosition9os.addItem("9*tau2/4");     choiceEkoPosition9os.addItem("5*tau2/2");
    choiceEkoPosition9os.select(4);               choiceEkoPosition9os.hide();  //

    choiceEkoPosition = choiceEkoPosition3;       choiceEkoPosition.show();

    textAreaDuree.setEditable(false);             textAreaIntensite.setEditable(false);
    buttonRun.move(50, 355);                      buttonRun.resize(100, hautBouton);
    panelTransition.add(buttonRun);

//******************************************************************************
//                 panelFitBouton et panelFitEstim dans panelFit
//******************************************************************************
    panelFit.setBackground(Color.orange);         panelFit.setLayout(null);
    panelFit.setFont(new Font("TimesRoman", Font.PLAIN, 12));

    labelExpIntensite.move(10, 7);                labelExpIntensite.resize(100, hautLB);
    panelFit.add(labelExpIntensite);
    textAreaExpIntensite.move(10, 30);            textAreaExpIntensite.resize(80, 150);
    panelFit.add(textAreaExpIntensite);
    textAreaParameter.move(10, 182);              textAreaParameter.resize(200, 170);
    panelFit.add(textAreaParameter);
    panelFitBouton.move(10, 355);                 panelFitBouton.resize(200, hautBouton);
    panelFit.add(panelFitBouton);                 panelFitBouton.setLayout(new GridLayout(1, 2));
    panelFitBouton.add(buttonPrevious);           panelFitBouton.add(buttonFit);
    buttonPrevious.enable(false);

    panelFitEstim.move(110, 5);                   panelFitEstim.resize(100, 176);
    panelFit.add(panelFitEstim);
    panelFitEstim.setBackground(Color.orange);    panelFitEstim.setLayout(new GridLayout(5, 1));
    panelFitEstim.setFont(new Font("TimesRoman", Font.PLAIN, 12));

    panelFitEstim.add(panelFitAlpha);
    panelFitEstim.add(new Label("RF field:"));    panelFitEstim.add(panelFitOmegaRF);
    panelFitEstim.add(new Label("OmegaQ:"));      panelFitEstim.add(panelFitQCC);

    choiceAlpha.addItem("1.1");                   choiceAlpha.addItem("1.2");
    choiceAlpha.addItem("1.3");                   choiceAlpha.addItem("1.4");
    choiceAlpha.select(2);
    panelFitOmegaRF.setLayout(new GridLayout(1, 2));
    panelFitOmegaRF.add(textFieldOmegaRFEst);     panelFitOmegaRF.add(new Label("  kHz"));
    panelFitQCC.setLayout(new GridLayout(1, 2));
    panelFitQCC.add(textFieldOmegaQEst);          panelFitQCC.add(new Label("  kHz"));
    panelFitAlpha.setLayout(new GridLayout(1, 2));
    panelFitAlpha.add(new Label("Alpha:"));       panelFitAlpha.add(choiceAlpha);
    panelFitEstim.hide();

    //valeurs exemples
    String s5 = 0.0+"\n"+-0.01088+"\n"+-0.04087+"\n"+-0.08264+"\n"+-0.12578+"\n";
    s5 += -0.1591+"\n"+-0.17312+"\n"+-0.16219+"\n"+-0.12578+"\n"+-0.06867+"\n"+0.0+"\n";
    s5 += 0.06867+"\n"+0.12578+"\n"+0.16219+"\n"+0.17312+"\n"+0.1591+"\n";
    s5 += 0.12578+"\n"+0.08264+"\n"+0.04087+"\n"+0.01088+"\n"+0.0+"\n";
    textAreaExpIntensite.setText(s5);
  }

  /**Start the applet*/
  public void 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 afficheTransition(){
    choiceTransition.hide();     choiceEkoPosition.hide();  // indispensable
    switch (choiceSpin.getSelectedIndex()) {
      case 0: choiceTransition = choiceTransition3;  choiceEkoPosition = choiceEkoPosition3;    break;
      case 1: choiceTransition = choiceTransition5;  choiceEkoPosition = choiceEkoPosition5is;  break;
      case 2: choiceTransition = choiceTransition7;  choiceEkoPosition = choiceEkoPosition7is;  break;
      case 3: choiceTransition = choiceTransition9;  choiceEkoPosition = choiceEkoPosition9is;  break;
    }
    choiceTransition.show();      choiceEkoPosition.show();     //pas nécessaire de selectionner
  }

  private void afficheEkoPosition(){
    choiceEkoPosition.hide();   //nécessaire
    switch (choiceSpin.getSelectedIndex()) {
      case 0: switch (choiceTransition.getSelectedIndex()) {
                default: choiceEkoPosition = choiceEkoPosition3;                break;
              }
              break;//spin 3/2
      case 1: switch (choiceTransition.getSelectedIndex()) {
                case 0: choiceEkoPosition = choiceEkoPosition5is;               break;
                case 1: choiceEkoPosition = choiceEkoPosition5os;               break;
              }
              break;//spin 5/2
      case 2: switch (choiceTransition.getSelectedIndex()) {
                case 0: choiceEkoPosition = choiceEkoPosition7is;               break;
                case 1: choiceEkoPosition = choiceEkoPosition7ms;               break;
                case 2: choiceEkoPosition = choiceEkoPosition7os;               break;
              }
              break;//spin 7/2
      case 3: switch (choiceTransition.getSelectedIndex()) {
                case 0: choiceEkoPosition = choiceEkoPosition9is;               break;
                case 1: choiceEkoPosition = choiceEkoPosition9ms;               break;
                case 2: choiceEkoPosition = choiceEkoPosition9nm;               break;
                case 3: choiceEkoPosition = choiceEkoPosition9os;               break;
              }
              break;//spin 9/2
    }
    choiceEkoPosition.show();
  }

  private void eko3sur2(){
    switch (choiceEkoPosition.getSelectedIndex()){
      default: ligne = 0;  colonne = 1;    break;    //au lieu de case 0: idem
    }                                                //qui crée des problèmes
  }

  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: ComplexMat.setTailleMatrice (4);
              coeff = 5.0;
              switch (choiceTransition.getSelectedIndex()){
                default: ligneST = 1;  pop = 2*Math.sqrt(3);  break;//satellites
              }
              eko3sur2();
              break; //spin 3/2
      case 1: 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; //spin 5/2
      case 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; //spin 7/2
      case 3: 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; //spin 9/2
    }
  }

  private void solomonEkoSequence(int i, double omegaQTmp, double omegaRFTmp, 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;
    Nmr myNmrTmp =  new Nmr(omegaQTmp, omegaRFTmp);   //OmegaQ, omegaRF en kHz

    //premiere impulsion +x
    matHH  = myNmrTmp.matriceHamilton(matHD, tp1);
    matHHC = myNmrTmp.matConjugue(matHH);
    matC1  = myNmrTmp.mult(matR2, matHH);    //effet de +x
    matC2  = myNmrTmp.mult(matHHC, matC1);   //effet de +x
    matC3  = myNmrTmp.mult(matC2, matRt);    //retour dans le ref tournant
    matC4  = myNmrTmp.mult(matR, matC3);     //retour dans le ref tournant
    if (choicePulseSequence.getSelectedIndex() == 1)
      matC4 = myNmrTmp.matRotation(matC4, Math.PI/2);
    matCz  = myNmrTmp.matQuatre(matC4, ligne, colonne);

    //seconde impulsion +x
    matC5  = myNmrTmp.mult(matCz, matR);     //passage dans le ref propre de matH
    matC6  = myNmrTmp.mult(matRt, matC5);    //passage dans le ref propre de matH
    matHH  = myNmrTmp.matriceHamilton(matHD, tp2);
    matHHC = myNmrTmp.matConjugue(matHH);
    matC7  = myNmrTmp.mult(matC6, matHH);    //effet de +x
    matC8  = myNmrTmp.mult(matHHC, matC7);   //effet de +x
    matC9  = myNmrTmp.mult(matC8, matRt);    //retour dans le ref tournant
    matC10 = myNmrTmp.mult(matR, matC9);     //retour dans le ref tournant
    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];
    }
  }

  private void calculIntensite(double omegaQTmp, double omegaRFTmp){
    RealMat      matH, matHD, matR, matRt, matIz, matR1, matR2;
    double       tp;
    Nmr myNmr =  new Nmr(omegaQTmp, omegaRFTmp);   //OmegaQ, omegaRF en kHz

    for (int i = 0; i < nbou + 1; i++){
      amplitudeReal[i] = 0.0;           amplitudeImag[i] = 0.0;  //RAZ
    }
    //impulsion x
    matH  = myNmr.dataIn();             //matrice matH à diagonaliser
    matHD = myNmr.jacRot(matH);         //matrice matH devient diagonale matHD
    matR  = myNmr.getMatR();            //matR est la matrice des vecteurs propres
    matRt = RealMat.transpose(matR);    //matRt est la matrice transposée de matR
    matIz = myNmr.matriceIz();          //etat equilibre
    matR1 = myNmr.mult(matIz, matR);    //etat equilibre dans le ref propre
    matR2 = myNmr.mult(matRt, matR1);   //de matH
    switch (choiceSequence.getSelectedIndex()){
      case 0:  //A(p1)B()
        for (int i = 0; i <= nbou; i++) {
          tp = dureePremiere + i*dureePas;
          solomonEkoSequence(i, omegaQTmp, omegaRFTmp, 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, omegaQTmp, omegaRFTmp, dureePremiere1, tp, matHD, matR, matRt, matR2);
        }
        break;
    }  //end of switch
  }

  private void afficheValeur(){     //affichage des résultats de durées et intensités
    double tp = 0;
    String s = "", s2 = "";
    textAreaIntensite.setText("");  //RAZ intensité
    textAreaDuree.setText("");      //RAZ durée
    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);
    }
  }

  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;
  }

  public boolean handleEvent(Event event){
    double milli = 0.001;
    switch (event.id){
      case Event.ACTION_EVENT:
        if (event.target == choiceSpin){
          textAreaIntensite.setText("");  //RAZ intensité
          textAreaDuree.setText("");      //RAZ durée
          panelCheckgroup.hide();
          afficheTransition();
        }
        else if (event.target == choicePulseSequence){
          textAreaIntensite.setText("");  //RAZ intensité
          textAreaDuree.setText("");      //RAZ durée
          panelCheckgroup.hide();
        }
        else if (event.target == choiceTransition){
          afficheEkoPosition();
        }
        else if (event.target == choiceSequence){
          switch (choiceSequence.getSelectedIndex()) {
            //A(p1)B()
            case 0: textFieldPremiereDuree.show();   textFieldDerniereDuree.show();
                    textFieldPas.show();
                    textFieldPremiereDuree2.show();  textFieldDerniereDuree2.hide();
                    textFieldPas2.hide();
                    break;
            //A()B(p2)
            case 1: textFieldPremiereDuree.show();   textFieldDerniereDuree.hide();
                    textFieldPas.hide();
                    textFieldPremiereDuree2.show();  textFieldDerniereDuree2.show();
                    textFieldPas2.show();
                    break;
          }
        }
        else if(event.target == checkboxReal){
          for (int i = 0; i < nbou + 1; i++) amplitude[i] = amplitudeReal[i];
          afficheValeur();
        }
        else if(event.target == checkboxImag){
          for (int i = 0; i < nbou + 1; i++) amplitude[i] = amplitudeImag[i];
          afficheValeur();
        }
        else if (event.target == buttonRun){
          normalisationSignal();
          switch (choiceSequence.getSelectedIndex()){
            case 0:  //A(p1)B()
              //convertit les durées de microsecondes en ms, car les interactions sont en kHz
              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)
              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];         //intensité du FID
          amplitudeReal =    new double[nbou + 1];         //intensité du FID reel
          amplitudeImag =    new double[nbou + 1];         //intensité du FID imaginaaire
          listExpIntensity = new double[nbou + 1];         //intensité exp
          calculIntensite(Double.valueOf(textFieldOmegaQ.getText()).doubleValue(),
                          Double.valueOf(textFieldOmegaRF.getText()).doubleValue());
          afficheValeur();
          panelFit.show();                       panelFitEstim.show();
          panelCheckgroup.show();
        }
        else if (event.target == buttonPrevious){
          panelSpin.show();                      panelBlanc.hide();  //pour impression
          //***modifie panelTransition et panelFit + 100
          panelTransition.move(260, 0);          panelTransition.show();
          panelFit.move(480, 0);                 buttonPrevious.enable(false);
          setBackground(Color.white);            panelSpin.setBackground(Color.pink);
          panelFit.setBackground(Color.orange);  panelTransition.setBackground(Color.pink);
          buttonGraph.hide();                    buttonFit.setLabel("Fit");
          buttonRun.enable(true);
        }
        else if (event.target == buttonFit){
          if (buttonFit.getLabel() == "Fit"){
            //conversion des intensités expérimentales en nombres
            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){   //controle le nombre de données
              textAreaParameter.setText("");
              textAreaParameter.appendText("The number of experimental" + "\n");
              textAreaParameter.appendText("intensities is wrong!!!" + "\n");
              textAreaParameter.appendText("May be type enter key" + "\n");
              textAreaParameter.appendText("for the last intensity data!!!");
            }
            else{  //demarrage du fit
              panelCheckgroup.hide();
              panelFit.move(300, 0);                setBackground(Color.pink);
              panelTransition.hide();               panelSpin.hide();
              panelBlanc.move(520 ,0);              panelBlanc.resize(240, hautPanel);
              add(panelBlanc);                      panelBlanc.show();  //***modifie panelBlanc +100
              panelBlanc.setBackground(Color.white);
              buttonFit.setLabel("StopFit");        buttonPrevious.enable(false);
              textAreaParameter.setText("");
              double alpha = Double.valueOf(choiceAlpha.getSelectedItem()).doubleValue();
              double val1 =  Double.valueOf(textFieldOmegaQEst.getText()).doubleValue();
              double val2 =  Double.valueOf(textFieldOmegaRFEst.getText()).doubleValue();
              //recherche de la valeur maximum de listExpIntensity[] et de 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
              choiceAlpha.enable(false);           textFieldOmegaRFEst.enable(false);
              textFieldOmegaQEst.enable(false);
              textAreaExpIntensite.enable(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(this);               th.start();
              buttonGraph.setLabel("DeactivateGraph");
              buttonGraph.show();                  buttonGraph.enable(true);
              labelAdvice.show();
              showCurve = true;                    stopFit = false;
            }
          }
          else{  //on arrete le fit
            stopFit = true;                        th = null;
            buttonPrevious.enable(true);           buttonFit.setLabel("Fit");
            choiceAlpha.enable(true);              textFieldOmegaRFEst.enable(true);
            textFieldOmegaQEst.enable(true);
            textAreaExpIntensite.enable(true);
            buttonGraph.enable(false);             labelAdvice.hide();
          }
        }
        else if (event.target == buttonGraph){
          if (buttonGraph.getLabel() == "DeactivateGraph"){
            showCurve = false;    buttonGraph.setLabel("ActivateGraph");     labelAdvice.hide();
            }
          else{
            showCurve = true;     buttonGraph.setLabel("DeactivateGraph");   labelAdvice.show();
          }
        }
      break;
    }  //end of switch
    return super.handleEvent(event);
  }

  private void plotCourbe(double b0, double b1, double b2){
    //tracer la courbe,(char) 181 = micron
    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();
  }

  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
    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.appendText(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;
      }

      //affiche les valeurs
      sx = Math.round(1000*matEstimation[bestI][1])/1000.0
          + " ( " + Math.round(1000*matEstimation[worstI][1])/1000.0 + " ) kHz\n";
      textAreaParameter.appendText("RF field: " + sx);
      sx = Math.round(1000*matEstimation[bestI][0])/1000.0
          + " ( " + Math.round(1000*matEstimation[worstI][0])/1000.0 + " ) kHz\n";
      textAreaParameter.appendText("OmegaQ: " + sx);
      sx = Math.round(1000*matEstimation[bestI][2])/1000.0
          + " ( " + Math.round(1000*matEstimation[worstI][2])/1000.0 + " )\n";
      textAreaParameter.appendText("Scale: " + sx);
      sx = y[bestI] + "\n";      textAreaParameter.appendText(sx);
      sx = y[worstI] + "\n";     textAreaParameter.appendText(sx);

      if (showCurve){
        try{Thread.sleep(1000);} catch (InterruptedException e){}
        //plotCourbe après try sinon clignotement avec 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]);

      //************************************************************************
      //                   debut du 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') est compris entre best y et les autres y, sauf A
            break;         //exit for
          }
        }

        if (flag){   //y1 ou f(A') n'est pas compris entre best y et les autres y sauf A
          if (y1 < y[worstI]){     //f(A') est compris entre best y et 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) ou f(B)>f(A'), TOUT CE QUE NOUS AVONS FAIT NE SERT A RIEN
            //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
      }
      //************************************************************************
      //                       fin de 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
    //**************************************************************************
  }

/*
  add(x, y)              Adds a point to a list. Expects points to come in x-order.
  graph()                Compulsory call
  graph(graphTitle, xAxisTitle, yAxisTitle)
                         Version with labelling options.
                         Use empty strings if not all titles applicable
  nextGraph()            Starts a new graph on the same axes.
                         One showGraph call can be used for all the graphs.
  setColor(int 0 to 3)   Choice of black, magenta, blue, red
                         (constants are available instead of numbers)
  setSymbol(boolean)     Deduced from the colour
                         (Convenient if colours are being set)
  setSymbol(int 0 to 3)  circle, upside down triangle, triangle, square
                         (Used if colours are not being set)
  setLine(boolean)       Normally on, can be turned off
                         (Remember to turn it on again for the next line)
  setTitle(String)       Will appear on a key alongside the symbol and/or
                         in the chosen colour
  */

  protected String xAxisTitle, yAxisTitle, graphTitle;
  protected boolean keys;
  protected int largeur = 300;  //largeur de la fenetre
  protected int hauteur = 340;  //hauteur de la fenetre

  protected void graph (String g, String x, String y) {
    // axes titles
    initializeGraph();    graphTitle = g;     xAxisTitle = x;       yAxisTitle = y;
  }

    protected void graph () {
    // axes titles
    initializeGraph();    graphTitle = "";    xAxisTitle = "";       yAxisTitle = "";
  }

  protected ListGentle points;
  protected ListGentle datasets;

  protected void initializeGraph () {
    datasets = new ListGentle ();     nextGraph();    points = new ListGentle ();
    xMax = yMax = Double.MIN_VALUE;    xMin = yMin = Double.MAX_VALUE;
    keys = false;
  }

  public void nextGraph () {
    Dataset d = new Dataset ();    d.count = 0;
    d.plotType = black;            d.title = "";
    d.symbolRequired = false;      d.colorRequired = false;
    d.titleRequired = false;       d.lineRequired = true;
    datasets.add (d);
  }

  public void setColor (int c) {
    ((Dataset) datasets.current()).colorRequired = true;
    ((Dataset) datasets.current()).plotType = c;
  }

  public void setSymbol (boolean b) {
    ((Dataset) datasets.current()).symbolRequired = b;
  }

  public void setSymbol (int c) {
    ((Dataset) datasets.current()).symbolRequired = true;
    ((Dataset) datasets.current()).plotType = c;
  }

  public void setTitle (String s) {
    ((Dataset) datasets.current()).titleRequired = true;
    ((Dataset) datasets.current()).title = s;
    keys = true;
  }

  public void setLine (boolean b) {
    ((Dataset) datasets.current()).lineRequired = b;
    if (b==false) ((Dataset) datasets.current()).symbolRequired = true;
  }

  public void add (double x, double y) {
    points.add (new PointDot (x,y));
    ((Dataset)datasets.current()).count++;
    if (x > xMax) xMax = x;    if (x < xMin) xMin = x;
    if (y > yMax) yMax = y;    if (y < yMin) yMin = y;
  }

  protected void drawTitles (Graphics g) {
    Dataset d;
    int x = xBorder + cent;  //legende
    int y = hauteur-yBorder/2 + cent;  //legende
    datasets.reset();
    boolean lastset = datasets.eol();
    while (!lastset) {
      d = (Dataset) datasets.current();
      if (d.colorRequired) changeColor(g, d.plotType);
      if (d.symbolRequired) {
        drawSymbol(g, d.plotType, x, y-cs);
        x += 4*cs;
      }
      g.drawString(d.title, x, y);
      x += g.getFontMetrics().stringWidth(d.title)+20;
      lastset = datasets.eol();
      if (!lastset) datasets.succ();
    }
    g.setColor(Color.black);
  }

  protected void drawAxes (Graphics g) {
    Font plain = g.getFont();
    Font small = new Font(plain.getFamily(), Font.PLAIN,10);
    Font bold  = new Font(plain.getFamily(), Font.BOLD,14);

    g.drawLine(xBorder-5 + cent,yOrigin,xAxisLength+xBorder+5 + cent,yOrigin);  //axe x
    g.drawLine(xOrigin,yBorder-5 + cent,xOrigin,yAxisLength+yBorder+5 + cent);  //axe y
    g.drawString(xAxisTitle,
      largeur-g.getFontMetrics().stringWidth(xAxisTitle)-xBorder/2 + cent, yOrigin-5);  //"x"
    g.drawString(yAxisTitle,
      xOrigin-g.getFontMetrics().stringWidth(yAxisTitle)/2, yBorder-8 + cent); //"y"

    g.setFont(bold);
    g.drawString(graphTitle,
      (largeur-g.getFontMetrics().stringWidth(graphTitle))/2, yBorder/2 + cent);  //titre
    g.setFont(plain);
    if (keys) drawTitles(g);

    // Tick and Label the four min/max points only
    int scaleXMin = scaleX(xMin);    int scaleXMax = scaleX(xMax);
    int scaleYMin = scaleY(yMin);    int scaleYMax = scaleY(yMax);
    g.drawLine(xOrigin-5, scaleYMax + cent, xOrigin+5, scaleYMax + cent); //tick yMax
    g.drawLine(xOrigin-5, scaleYMin + cent, xOrigin+5, scaleYMin + cent); //tick yMin
    g.drawLine(scaleXMax + cent, yOrigin+5, scaleXMax + cent, yOrigin);  //tick xMax
    g.drawLine(scaleXMin + cent, yOrigin+5, scaleXMin + cent, yOrigin);  //tick xMin

    g.setFont(small);
    g.drawString(Double.toString(xMin),scaleXMin-10 + cent,yOrigin+15);  //xMin
    g.drawString(Double.toString(xMax),scaleXMax-10 + cent,yOrigin+15);  //xMax
    g.drawString(Double.toString(Math.round(100*yMin)/100.0), xOrigin-35, scaleYMin+4 + cent);  //yMin
    g.drawString(Double.toString(Math.round(100*yMax)/100.0), xOrigin-35, scaleYMax+4 + cent);  //yMax
    g.setFont(plain);
  }

  protected double xSpread, ySpread, xMin, xMax, yMin, yMax;
  protected int xAxisLength, yAxisLength, xOrigin, yOrigin;
  protected int xBorder, yBorder;

  public void paint (Graphics g) {
    // calulate length of axes from window size minus a border of 20
    xBorder = 40;    yBorder = 80;
    xAxisLength = (int) largeur - 2*xBorder;    yAxisLength = (int) hauteur - 2*yBorder;

    // calculate value spreads from mins and maxs which have been recorded as we go
    xSpread = xMax - xMin;    ySpread = yMax - yMin;
    if (xMin > 0) xOrigin = scaleX(xMin) + cent; else xOrigin = scaleX(0) + cent;
    if (yMin > 0) yOrigin = scaleY(yMin) + cent; else yOrigin = scaleY(0) + cent;
    drawAxes(g);    plotGraphs(g);
  }

  protected int scaleX(double x) {
    return (int) ((x-xMin) / xSpread*xAxisLength) + xBorder ;
  }

  protected int scaleY(double y) {
    return (int) (yAxisLength - ((y-yMin) / ySpread*yAxisLength)) + yBorder;
  }

  protected void changeColor(Graphics g, int c) {
    switch (c) {
      case black :   {g.setColor(Color.black); break;}
      case magenta : {g.setColor(Color.magenta); break;}
      case blue :    {g.setColor(Color.blue); break;}
      case red :     {g.setColor(Color.red); break;}
    }
  }

  protected static final int cs = 3; // pixel size of a symbol

  protected void drawSymbol (Graphics g, int sy, int x, int y) {
    switch (sy) {
      case black :   {g.drawOval (x-cs, y-cs, 2*cs, 2*cs); break;}
      case magenta : {g.drawPolygon (trix(x),uptriy(y), 3); break;}
      case blue :    {g.drawPolygon (trix(x),triy(y), 3); break;}
      case red :     {g.drawRect (x-cs, y-cs, 2*cs, 2*cs); break;}
    }
  }

  protected void plotGraphs (Graphics g) {
    PointDot p, q;    int x1, y1, x2, y2;    Dataset d;    boolean lastset;    Color c;

    // Loop through each dataset
    datasets.reset();
    /* The points are in one big list, split by the
    counts recorded in each dataset */
    points.reset();
    lastset = datasets.eol();

    do {
      d = (Dataset) datasets.current();
      if (d.colorRequired) changeColor(g, d.plotType);
      // Start with the first point in the list for this graph
      p = (PointDot) points.current();
      x1 = scaleX(p.xCoord) + cent;      y1 = scaleY(p.yCoord) + cent;
      if (d.symbolRequired) drawSymbol(g, d.plotType, x1, y1);

      // Loop through the points as stored in the list
      for (int i=1; i<d.count; i++) {
        points.succ();                         q = (PointDot) points.current();
        x2 = scaleX(q.xCoord) + cent;          y2 = scaleY(q.yCoord) + cent;

        // plot the line and/or point
        if (d.lineRequired)   g.drawLine(x1, y1, x2, y2);
        if (d.symbolRequired) drawSymbol(g, d.plotType, x2, y2);
        x1 = x2; y1 = y2;
      }
      lastset = datasets.eol();
      if (!lastset) {
        datasets.succ();
        points.succ();
      }
    } while (!lastset);
  }

  protected int [] trix (int p) {
    int [] a = new int [3];
    a[0] = p-cs;    a[1] = p+cs;    a[2] = p;
    return a;
  }

  protected int [] triy (int p) {
    int [] a = new int [3];
    a[0] = p+cs;    a[1] = p+cs;    a[2] = p-cs;
    return a;
  }

  protected int [] uptriy (int p) {
    int [] a = new int [3];
    a[0] = p-cs;    a[1] = p-cs;    a[2] = p+cs;
    return a;
  }

  public final int red = 3;       public final int blue = 2;
  public final int magenta = 1;   public final int black = 0;
}

class PointDot {
  /* simple class for an x,y coordinate */
  double xCoord, yCoord;
  PointDot (double x, double y) {
    xCoord = x;    yCoord = y;
  }
}

class Dataset {
  /* Simple class for recording basic info about a set of points.
  Allows more than one graph to be drawn on an axis.
  All initialisation done in nextGraph. */
  int count, plotType;      String title;
  boolean colorRequired, symbolRequired, titleRequired, lineRequired;
}
