Android

Android


C.3. Energía del Helio-4

Página 23 de 25

APÉNDICE C

APLICACIONES

En este apéndice aplicamos los conceptos y técnicas introducidas en este libro para realizar un programa completo de cálculo científico, con aplicación directa al cálculo de la estructura del núcleo de helio. Esta aplicación puede descargarse de la página web http://www.ugr.es/~amaro/android e instalarse directamente en un dispositivo Android. El código fuente también se encuentra disponible para su descarga. Para comprender la estructura de este programa no se necesitan conocimientos previos de Física, pues bastaría indicar que se calculan las ecuaciones (C.1) a (C.5) a partir de los parámetros de entrada y de los datos experimentales, que se descargan de la red según se explica más abajo. Ahora bien, para el lector más avanzado y curioso, incluimos en cada sección una pequeña introducción para aclarar el significado de las ecuaciones, el de los parámetros de entrada y el de las magnitudes que se están calculando.

C.1. Interacción neutrón-protón

En el siguiente programa calcularemos (más bien ajustaremos) la energía potencial de interacción entre un neutrón y un protón. El programa puede utilizarse en un curso de Física Cuántica como ilustración de la resolución de la ecuación de ondas (ecuación de Schrödinger) en una dimensión.

donde u(r) es la función de onda relativa del sistema neutrón-protón, r es la distancia entre las dos partículas y ε>0 es la energía relativa multiplicada por 2μ/ħ

2

, siendo μ = m/2 la masa reducida y m la masa del protón. La constante de Plank reducida es ħ = h/2π. Queremos encontrar la energía potencial U(r), parametrizada en la forma:

donde λ

0

, λ

1

, R

0

, R

1

, son cuatro parámetros que se van a ajustar en el programa comparando con datos experimentales de la interacción. Este potencial lo hemos parametrizado como suma de dos funciones del tipo delta de Dirac, centradas en los puntos R

0

y R

1

, indicando que la interacción sucede en esos dos puntos. La función delta de Dirac δ (x) verifica:

•   δ (x) = 0, si x es distinto de cero, y

•   ∫ δ(x)dx = 1, en cualquier intervalo conteniendo al cero.

Para este programa no necesitamos conocer los detalles de la resolución de la ecuación de ondas con el potencial anterior. Nos basta con tener la expresión matemática de la función solución u(r), que está dada en la sección C.2..

La actividad principal de este programa es el siguiente fichero  HandroicPhysics.java. Utilizaremos el layout introducido en el ejemplo 13.3, que consta de los tres ficheros main.xml, strings.xml, colors.xml.

  package es.ugr.amaro.handroicphysics;

  import android.app.Activity;

  import android.content.Intent;

  import android.content.SharedPreferences;

  import android.os.Bundle;

  import android.view.View;

  import android.view.View.OnClickListener;

  import android.widget.EditText;

  import android.widget.Toast;

  public class HandroicPhysics extends Activity implements

                                      OnClickListener{

    SharedPreferences misDatos;

    EditText editL00,editL01;

    EditText editL10,editL11;

    EditText editR00,editR01;

    EditText editR10,editR11;

    EditText editEmax,editTolerancia,editResolucion;

     @Override

     public void onCreate(Bundle savedInstanceState) {

         super.onCreate(savedInstanceState);

         setContentView(R.layout.main);

     }

     @Override

     protected    void onStart(){

      super.onStart();

         View button1=findViewById(R.id.button1);

         View button2=findViewById(R.id.button2);

         View button3=findViewById(R.id.button3);

         button1.setOnClickListener(this);

         button2.setOnClickListener(this);

         button3.setOnClickListener(this);

         // lee lambad00 en el fichero de preferencias

         misDatos=getSharedPreferences("preferencias",0);

         editEmax=(EditText) findViewById(R.id.Emax);

         editEmax.setText(""+misDatos.getFloat("Emax",100));

         editTolerancia=

                 (EditText) findViewById(R.id.tolerancia);

         editTolerancia.setText(""+

                 misDatos.getFloat("tolerancia",0.5f));

         editResolucion=

                 (EditText) findViewById(R.id.resolucion);

         editResolucion.setText(""

             +misDatos.getFloat("resolucion",(float) 1e-5));

         editR00=(EditText) findViewById(R.id.R00);

         editR01=(EditText) findViewById(R.id.R01);

         editR00.setText(""+misDatos.getFloat("R00", 0.75f));

         editR01.setText(""+misDatos.getFloat("R01", 1.25f));

         editR10=(EditText) findViewById(R.id.R10);

         editR11=(EditText) findViewById(R.id.R11);

         editR10.setText(""+misDatos.getFloat("R10", 0.75f));

         editR11.setText(""+misDatos.getFloat("R11", 1.25f));

         editL00=(EditText) findViewById(R.id.lambda00);

         editL01=(EditText) findViewById(R.id.lambda01);

         editL10=(EditText) findViewById(R.id.lambda10);

         editL11=(EditText) findViewById(R.id.lambda11);

         editL00.setText(""

                 + misDatos.getFloat("lambda00", 0.73f));

         editL01.setText(""

                 + misDatos.getFloat("lambda01",-0.7f));

         editL10.setText(""

                 + misDatos.getFloat("lambda10", 0.73f));

         editL11.setText(""

                 + misDatos.getFloat("lambda11",-0.7f));

     }

     @Override

     protected void onPause(){

       super.onPause();

       SharedPreferences.Editor miEditor=misDatos.edit();

       float dato;

       dato=Float.parseFloat(editR00.getText().toString());

       miEditor.putFloat("R00",dato);

       dato=Float.parseFloat(editR01.getText().toString());

       miEditor.putFloat("R01",dato);

       dato=Float.parseFloat(editR10.getText().toString());

       miEditor.putFloat("R10",dato);

       dato=Float.parseFloat(editR11.getText().toString());

       miEditor.putFloat("R11",dato);

       dato=Float.parseFloat(editL00.getText().toString());

       miEditor.putFloat("lambda00",dato);

       dato=Float.parseFloat(editL01.getText().toString());

       miEditor.putFloat("lambda01",dato);

       dato=Float.parseFloat(editL10.getText().toString());

       miEditor.putFloat("lambda10",dato);

       dato=Float.parseFloat(editL11.getText().toString());

       miEditor.putFloat("lambda11",dato);

       dato=Float.parseFloat(editEmax.getText().toString());

       miEditor.putFloat("Emax",dato);

       dato=Float.parseFloat(

               editTolerancia.getText().toString());

       miEditor.putFloat("tolerancia",dato);

       dato=Float.parseFloat(

               editResolucion.getText().toString());

       miEditor.putFloat("resolucion",dato);

       miEditor.commit();

       Toast.makeText(this,"Datos guardados",1).show();

     }

    @Override

    public void onClick(View v) {

       int i=v.getId();

       Intent intencion;

       if(i==R.id.button1){

          // calcula la energia del He4

          intencion=new Intent(this,He4.class);

          startActivity(intencion);

       }

       else if(i==R.id.button2){

          // calcula desfasaje para spin=0

          intencion=new Intent(this,PhaseShift.class);

          intencion.putExtra(PhaseShift.spinExtra, 0);

          startActivity(intencion);

       }

       else if(i==R.id.button3){

          // calcula desfasaje para spin=1

          intencion=new Intent(this,PhaseShift.class);

          intencion.putExtra(PhaseShift.spinExtra, 1);

          startActivity(intencion);

       }

    }

  }

La actividad puede verse en la figura C.1 (que es la misma del ejemplo 13.3). La actividad tiene tres botones y 11 campos de texto.

Figura C.1. Interfaz de usuario para ajustar la interacción neutrón-protón y para calcular la energía del helio-4.

Debemos aclarar que la interacción depende de una variable del protón y neutrón denominada espín. El espín total puede ser cero o uno. La interacción para espín cero se denomina el canal

1

S

0

y la interacción para espín uno el canal

3

S

1

. De manera que debemos encontrar dos conjuntos de parámetros, uno para cada canal. En la primera columna hay que introducir los valores iniciales de los cuatro parámetros λ

0

, λ

1

, R

0

, R

1

, para el canal

1

S

0

. En la segunda columna introducimos los valores para los cuatro parámetros en el canal

3

S

1

. Los valores de R

i

están en unidades de Fermi (fm) (1 Fermi = 10

-15

metros) y los de λ

i

en fm

-1

. En la última fila hay tres campos de texto. El primero, E

max

, es la máxima energía experimental que vamos a incluir en el ajuste posterior, en la figura es de 100 MeV (Mega electrón Voltios). El segundo es la tolerancia, que es el mínimo error experimental que aceptamos. En el ejemplo es de 0.5, indicando que el error experimental no puede ser menor de 0.5 (si es menor, lo modificamos para que sea exactamente 0.5). El tercer campo es la resolución, que corresponde a la última cifra decimal de nuestros parámetros, que se va a variar en el ajuste. En este caso es de 10

-5

.

En la actividad HandroicPhysics.java definimos tres botones marcados A, B, C. Al pulsar el primero, se ajustan o calculan los parámetros del canal

1

S

0

. Al pulsar el segundo, se ajusta el canal

3

S

1

. El tercer botón se utilizará para calcular la energía de ligadura del núcleo de

4

He (Helio 4) o partícula alfa.

Cada vez que se inicia la actividad anterior y se ejecuta el método onStart(), los contenidos de los campos de texto se leen de un fichero de preferencias con SharedPreferences. De la misma forma, cuando salimos de la actividad (al pulsar un botón o la tecla back), se ejecuta el método onPause() y se guardan los contenidos de los campos de texto en el fichero de preferencias.

C.2. Ajuste por mínimos cuadrados

Al pulsar el botón A se ajustan los parámetros del canal

1

S

0

. Para ello utilizamos que el potencial es cero en los puntos r distintos de R

0

y R

1

(puesto que la delta de Dirac es cero). Por tanto, la función de onda solución del problema en cada intervalo es una función trigonométrica, correspondiente a una partícula libre con número de ondas

, y se puede escribir:

donde δ

0

y δ

1

son fases constantes que se determinan imponiendo que la función de onda sea continua y que su derivada sea discontinua con una discontinuidad dada por:

propiedad que se obtiene integrando la ecuación de ondas en un intervalo alrededor de R

i

y usando la propiedad de integración de la delta de Dirac. El resultado son las siguientes ecuaciones, que emplearemos para calcular las fases:

y:

Se puede calcular así el desfase total o desfasaje:

El desfasaje se calcula a partir de las ecuaciones (C.1) a (C.3) en el programa siguiente PhaseShift.java. Este desfasaje δ es debido a la interacción y puede medirse experimentalmente haciendo incidir haces de neutrones sobre núcleos de hidrógeno (protones). Existen varias parametrizaciones para los datos experimentales del desfasaje. Algunas de ellas se pueden descargar de la página web nucleon-nucleon online:

http://nn.online.org/NN

En esta página web seleccionaremos Phase shifts versus energy (table), lo que nos lleva a una página donde podemos elegir las siguientes opciones:

•   Choose model. Seleccionaremos todos los modelos.

•   Choose interaction. Seleccionaremos la interacción neutrón-protón.

•   Energy interval. Seleccionaremos el intervalo de energía Tmin=1 MeV, Tmax=350 MeV.

•   Intervals of energy. Introduciremos un intervalo de 1 MeV.

•   Give the phase. Introduciremos el canal deseado, en este caso 1S0.

Al enviar estos datos, se mostrará en pantalla una tabla con la información deseada. La descargaremos en un fichero, llamado phase1s0.txt (para el caso 3S1 haremos lo mismo, llamando al fichero phase3s1.txt), que contendrá el desfasaje experimental para energías desde 1 MeV hasta 350 MeV, con un intervalo de energía de 1 MeV, que copiaremos en el directorio /res/raw de nuestro proyecto. Cada fila contiene el valor de la energía en la primera columna, y, en las restantes columnas, el desfasaje calculado con varios modelos. Tomando el valor medio de estos desfasajes, obtenemos el que consideraremos desfasaje experimental. La variación (máximo menos mínimo) de estos desfasajes es lo que consideraremos el error experimental. De este fichero seleccionamos un conjunto de valores { (E

i

, δ

i

, Δ

i

) : i=1,…,n } para la energía, desfasaje experimental y su error, respectivamente.

A continuación, lo que haremos en el programa será lo siguiente:

1.  Elegir un conjunto de parámetros del potencia.

2.  Calcular el desfasaje δ(E

i

) mediante las fórmulas anteriores.

3.  Calcular la función chi cuadrado:

Este número es una estimación de la distancia global a los datos experimentales.

4.  Modificar los parámetros del potencial y repetir el proceso, recalculando la función chi cuadrado hasta encontrar el mínimo.

El funcionamiento del programa para el canal

1

S

0

se ilustra en la figura C.2. Consiste en una animación donde se dibuja el desfasaje experimental en función de la energía y los puntos calculados, que se van modificando en cada iteración hasta que se alcanza el mínimo con la resolución deseada. Al finalizar, pulsamos la tecla back y los nuevos valores del potencial aparecen en los campos de texto de la primera columna, figura C.3. El listado del programa PhaseShift.java es el siguiente.

  package es.ugr.amaro.handroicphysics;

  import java.io.BufferedReader;

  import java.io.InputStream;

  import java.io.InputStreamReader;

  import java.util.StringTokenizer;

  import android.app.Activity;

  import android.content.Context;

  import android.content.SharedPreferences;

  import android.graphics.Canvas;

  import android.graphics.Color;

  import android.graphics.Paint;

  import android.graphics.Path;

  import android.os.Bundle;

  import android.view.View;

  import android.widget.Toast;

  public class PhaseShift extends Activity {

    public static final String spinExtra="spin";

    SharedPreferences misDatos;

    final int ndeltas=2; // numero de deltas

    final int nparametros=2*ndeltas;

    int spin;

    double[] energy=new double[400];

    double[][] dat=new double[400][5];

    double[] energyExp ={1,3,5,10,20,30,40,50,70,

                   100,150,200,250,300,350};

    int nDatos,nDatosExp;

    double[] expdat=new double[20];

    double[] expdatError= new double[20];

    double[] deltaDeg=new double[20];

    Plot plot;

    String texto,texto1;

    String texto2="Paso";

    String texto3="CALCULANDO...";

    double lambda[][]=new double[2][ndeltas];

    double Rdelta[][]=new double[2][ndeltas];

    double Emax;

    boolean continuar=true;

    Thread hilo;

    //variables para minimizar

    double[] xvar = new double[2*ndeltas];

    double tolerancia,resolucion;

    @Override

    public void onCreate(Bundle savedInstanceState){

       super.onCreate(savedInstanceState);

       // spin pasado en parametro extra

       spin=getIntent().getIntExtra(spinExtra, 0);

       leerPreferencias();

       leerDatos();

       plot=new Plot(this);

       setContentView(plot);

       hilo=new Thread(plot);

       hilo.start();

    }

    class Plot extends View implements Runnable{

       int width,height;

       Paint paint1,paint2,pain3,paint,paintRun;

       Path path1;

       int topMargin=30;

       int margin=30;

       int x0,x1,y0,y1,x,y;

       double e0,e1,d0,d1;

       public Plot(Context context) {

          super(context);

          paint=new Paint();

          paint.setColor(Color.BLACK);

          paint.setTextSize(16);

          paintRun=new Paint();

          paintRun.setColor(Color.RED);

          paintRun.setTextSize(20);

          paint1=new Paint();

          paint1.setColor(Color.BLACK);

          paint1.setStyle(Paint.Style.STROKE);

          paint1.setStrokeWidth(1);

          paint2=new Paint();

          paint2.setColor(Color.RED);

          paint2.setStyle(Paint.Style.STROKE);

          paint2.setStrokeWidth(3);

          path1=new Path();  

          e0=0;

          e1=350;

          d0=-20;

          d1=180;

       }

       @Override

       protected void onSizeChanged(

                int w, int h, int oldw, int oldh){

          width=w;

          height=h;

          x0=margin;

          x1=width-margin;

          y0=height/2;

          y1=topMargin;

       }

       @Override

       protected void onDraw (Canvas canvas){

          canvas.drawColor(Color.WHITE);

          texto="Desfasaje Neutron-Proton. SPIN="+spin;

          canvas.drawText(texto,20,20,paint);

          canvas.drawRect(x0,y0,x1,y1,paint1);

          canvas.drawText(texto1,

                 width/2-30,topMargin+20,paint);

          canvas.drawText(texto2,

                 width/2-30,topMargin+40,paint);

          canvas.drawText(texto3,

             width/2-30,topMargin+65, paintRun);

          x=coX(energy[0]);

          y=coY(dat[0][0]);

          path1.moveTo(x,y);

          for(int ie=1;ie<nDatos;ie++){

             x=coX(energy[ie]);

             y=coY(dat[ie][0]);

             path1.lineTo(x,y);

          }

          canvas.drawPath(path1,paint2);

          // dibuja puntos experimentales

          for (int i=0;i< nDatosExp;i++){

             x=coX(energyExp[i]);

             y=coY(expdat[i]);

             int y1=coY(expdat[i]-expdatError[i]);

             int y2=coY(expdat[i]+expdatError[i]);

             canvas.drawCircle(x, y, 5 , paint);

             canvas.drawLine(x,y1,x,y2, paint);

             // dibuja puntos ajustados

             y=coY(deltaDeg[i]);

             canvas.drawCircle(x,y,5,paint2);

          }

          // Marcas en el eje x

          for (int i=0; i<7;i++){

             canvas.drawLine(coX(50*i),coY(d0),

                         coX(50*i),coY(d0+5),paint1);

             canvas.drawText(""+50*i,

                         coX(50*i),coY(d0)+20, paint);

          }

          // Marcas en el eje y

          for (int i=0;i<18;i++){

             canvas.drawLine(coX(0),coY(10*i),

                         coX(0+5),coY(10*i), paint1);

             canvas.drawText(""+10*i,0,coY(10*i), paint);

          }

          // dibuja linea del cero

          canvas.drawLine(coX(0),coY(0),

                                 coX(350),coY(0),paint1);

          // escribe parametros del potencial

          texto="R"+spin+"0 ="+xvar[2];

          canvas.drawText(texto, 20, y0+40, paint);

          texto="La"+spin+"0 ="+xvar[0];

          canvas.drawText(texto, 20, y0+60, paint);

          texto="R"+spin+"1 ="+xvar[3];

          canvas.drawText(texto, 20, y0+80, paint);

          texto="La"+spin+"1 ="+xvar[1];

          canvas.drawText(texto, 20, y0+100, paint);

          canvas.drawText("Emax="+Emax, 20, y0+120, paint);

          int ii=2;

          // escribe puntos experimentales

          texto="ndatosExp="+nDatosExp;

          canvas.drawText(texto,width/2+10,y0+20*ii,paint);

          for (int i=0;i<nDatosExp;i++){

             ii++;

             texto="/"+energyExp[i]+"/"

                       +expdat[i]+"/"+expdatError[i];

             canvas.drawText(texto,width/2+10,y0+20*ii,paint);

          }

       }

       int coX(double e){

          double xdouble=x0+(x1-x0)*(e-e0)/(e1-e0);        

          return (int) xdouble;

       }

       int coY(double d){

          double ddouble=y0+(y1-y0)*(d-d0)/(d1-d0);

          return (int) ddouble;

       }

       @Override

       public void run() {

          // Comienza buscando el minimo con paso inicial

          double paso=0.5;

          int dt=200;

          while(continuar){

             texto2="Paso="+paso;

             minimiza(paso);

             paso=paso/2.0;

             postInvalidate();

             try{ Thread.sleep(dt);}

             catch(InterruptedException e){;}

             if(paso/2.<resolucion)continuar=false;

          }

          texto3="MINIMO ENCONTRADO!";

          postInvalidate();

       }

    }

    void leerDatos(){

       int numeroFichero=R.raw.phase1s0;

       if(spin==1) numeroFichero=R.raw.phase3s1;

       InputStream input1=

           getResources().openRawResource(numeroFichero);

       InputStreamReader stream1=

                  new InputStreamReader(input1);

       BufferedReader buffer1=

                         new BufferedReader(stream1,8192);

       int iLinea=0;

       int iDato=0;

       try{

          String linea;

          while(true){

             linea=buffer1.readLine();

             if(linea==null)break;

             iLinea++;

             if(iLinea>4){

             StringTokenizer tokens =

                    new StringTokenizer(linea);

             energy[iDato]=

                  Double.parseDouble(tokens.nextToken());

             // lee cinco columnas

             // con varios calculos de  desfasajes

             for (int j=0; j<5; j++){

             dat[iDato][j]=

                Double.parseDouble(tokens.nextToken());

             }

             iDato++;

           }

         }

         input1.close();

         stream1.close();

         buffer1.close();

       }catch(Exception e){

         texto="\n"+e;

       }

       nDatos=iDato;

       texto=texto+"Datos: "+nDatos;

       // calcula puntos experimentales

       nDatosExp=0;

       for (int i=0;energyExp[i]<=Emax;i++){

         for (int j=0; j<nDatos; j++){

             double diff=energyExp[i]-energy[j];

             if (Math.abs(diff)<0.01){

                double datMin=dat[j][0];

                double datMax=datMin;

                for(int k=1;k<5;k++){

                   double dato=dat[j][k];

                   if (datMax < dato)datMax=dato;

                   if(datMin > dato)datMin=dato;

                }

Ir a la siguiente página

Report Page